int KX_NavMeshObject::FindPath(const MT_Point3& from, const MT_Point3& to, float* path, int maxPathLen)
{
	if (!m_navMesh)
		return 0;
	MT_Point3 localfrom = TransformToLocalCoords(from);
	MT_Point3 localto = TransformToLocalCoords(to);
	float spos[3], epos[3];
	localfrom.getValue(spos); flipAxes(spos);
	localto.getValue(epos); flipAxes(epos);
	dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt);
	dtStatPolyRef ePolyRef = m_navMesh->findNearestPoly(epos, polyPickExt);

	int pathLen = 0;
	if (sPolyRef && ePolyRef)
	{
		dtStatPolyRef* polys = new dtStatPolyRef[maxPathLen];
		int npolys;
		npolys = m_navMesh->findPath(sPolyRef, ePolyRef, spos, epos, polys, maxPathLen);
		if (npolys)
		{
			pathLen = m_navMesh->findStraightPath(spos, epos, polys, npolys, path, maxPathLen);
			for (int i=0; i<pathLen; i++)
			{
				flipAxes(&path[i*3]);
				MT_Point3 waypoint(&path[i*3]);
				waypoint = TransformToWorldCoords(waypoint);
				waypoint.getValue(&path[i*3]);
			}
		}

		delete[] polys;
	}

	return pathLen;
}
Beispiel #2
0
/**
 * Returns the center of the circle defined by three points.
 * @param p1 point
 * @param p2 point
 * @param p3 point
 * @param center circle center
 * @return false if points are collinears, true otherwise
 */
bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
						 MT_Point3& center)
{
	// Compute quad plane
	MT_Vector3 p1p2 = p2-p1;
	MT_Vector3 p1p3 = p3-p1;
	MT_Plane3 plane1(p1,p2,p3);
	MT_Vector3 plane = plane1.Normal();
	
	// Compute first line vector, perpendicular to plane vector and edge (p1,p2)
	MT_Vector3 vL1 = p1p2.cross(plane);
	if( MT_fuzzyZero(vL1.length() ) )
			return false;
	vL1.normalize();
	
	// Compute first line point, middle point of edge (p1,p2)
	MT_Point3 pL1 = p1.lerp(p2, 0.5);

	// Compute second line vector, perpendicular to plane vector and edge (p1,p3)
	MT_Vector3 vL2 = p1p3.cross(plane);
	if( MT_fuzzyZero(vL2.length() ) )
			return false;
	vL2.normalize();
	
	// Compute second line point, middle point of edge (p1,p3)
	MT_Point3 pL2 = p1.lerp(p3, 0.5);

	// Compute intersection (the lines lay on the same plane, so the intersection exists
    // only if they are not parallel!!)
	return BOP_intersect(vL1,pL1,vL2,pL2,center);
}
Beispiel #3
0
MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_Point3& orig,
							 const MT_Vector3& dir,
							 const MT_Vector3 up)
{
	MT_Vector3 z = -(dir.normalized());
	MT_Vector3 x = (up.cross(z)).normalized();
	MT_Vector3 y = (z.cross(x));
	
	m_V[0][0] = x.x();
	m_V[0][1] = y.x();
	m_V[0][2] = z.x();
	m_V[0][3] = 0.0f;
	
	m_V[1][0] = x.y();
	m_V[1][1] = y.y();
	m_V[1][2] = z.y();
	m_V[1][3] = 0.0f;
	
	m_V[2][0] = x.z();
	m_V[2][1] = y.z();
	m_V[2][2] = z.z();
	m_V[2][3] = 0.0f;
	
	m_V[3][0] = orig.x();//0.0f;
	m_V[3][1] = orig.y();//0.0f;
	m_V[3][2] = orig.z();//0.0f;
	m_V[3][3] = 1.0f;
	
	//Translate(-orig);
}
Beispiel #4
0
bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback)
{
	if(physics_environment==NULL) return false; /* prevents crashing in some cases */
	
	// Loops over all physics objects between frompoint and topoint,
	// calling callback.RayHit for each one.
	//
	// callback.RayHit should return true to stop looking, or false to continue.
	//
	// returns true if an object was found, false if not.
	
	MT_Point3 frompoint(_frompoint);
	const MT_Vector3 todir( (topoint - frompoint).safe_normalized() );
	MT_Point3 prevpoint(_frompoint+todir*(-1.f));
	
	PHY_IPhysicsController* hit_controller;

	while((hit_controller = physics_environment->rayTest(callback,
			frompoint.x(),frompoint.y(),frompoint.z(),
			topoint.x(),topoint.y(),topoint.z())) != NULL) 
	{
		KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo());
		
		if (!info)
		{
			printf("no info!\n");
			MT_assert(info && "Physics controller with no client object info");
			break;
		}
		
		// The biggest danger to endless loop, prevent this by checking that the
		// hit point always progresses along the ray direction..
		prevpoint -= callback.m_hitPoint;
		if (prevpoint.length2() < MT_EPSILON)
			break;

		if (callback.RayHit(info))
			// caller may decide to stop the loop and still cancel the hit
			return callback.m_hitFound;

		// Skip past the object and keep tracing.
		// Note that retrieving in a single shot multiple hit points would be possible 
		// but it would require some change in Bullet.
		prevpoint = callback.m_hitPoint;
		/* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */
		MT_Scalar marg = 0.001 + hit_controller->GetMargin();
		marg *= 2.f;
		/* Calculate the other side of this object */
		MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal));
		if (h <= 0.01)
			// the normal is almost orthogonal to the ray direction, cannot compute the other side
			break;
		marg /= h; 
		frompoint = callback.m_hitPoint + marg * todir;
		// verify that we are not passed the to point
		if ((topoint - frompoint).dot(todir) < 0.f)
			break;
	}
	return false;
}
/**
 * Returns which of vertex v1 or v2 is nearest to u.
 * @param mesh mesh that contains the faces, edges and vertices
 * @param u reference vertex index
 * @param v1 first vertex index
 * @param v2 second vertex index
 * @return the nearest vertex index
 */
BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2)
{
	MT_Point3 q = mesh->getVertex(u)->getPoint();
	MT_Point3 p1 = mesh->getVertex(v1)->getPoint();
	MT_Point3 p2 = mesh->getVertex(v2)->getPoint();
	if (BOP_comp(q.distance(p1), q.distance(p2)) > 0) return v2;
	else return v1;
}
Beispiel #6
0
/**
 * Pre: p0, p1 and q are collinears.
 * @param p0 point
 * @param p1 point
 * @param q point
 * @return 0 if q == p0, 1 if q == p1, or a value between 0 and 1 otherwise
 *
 * (p0)-----(q)------------(p1)
 *   |<-d1-->|               |
 *   |<---------d0---------->|
 * 
 */
MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q)
{
	MT_Scalar d0 = p0.distance(p1);
	MT_Scalar d1 = p0.distance(q);
	MT_Scalar d;
	
	if (BOP_fuzzyZero(d0)) d = 1.0;
	else if (BOP_fuzzyZero(d1)) d = 0.0;
	else d = d1 / d0;
	return d;
}
Beispiel #7
0
/**
 * Returns if points p4 or p5 is inside the circle defined by p1, p2 and p3.
 * @param p1 point
 * @param p2 point
 * @param p3 point
 * @param p4 point
 * @param p5 point
 * @return true if p4 or p5 is inside the circle, false otherwise. If 
 * the circle does not exist (p1, p2 and p3 are collinears) returns true
 */
bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
						const MT_Point3& p4, const MT_Point3& p5)
{
	MT_Point3 center;
	bool ok = BOP_getCircleCenter(p1,p2,p3,center);

	if (!ok) return true; // Collinear points!

	// Check if p4 or p5 is inside the circle
	MT_Scalar r = p1.distance(center);
	MT_Scalar d1 = p4.distance(center);
	MT_Scalar d2 = p5.distance(center);
	return (BOP_comp(d1,r) <= 0 || BOP_comp(d2,r) <= 0);
}
float KX_NavMeshObject::Raycast(const MT_Point3& from, const MT_Point3& to)
{
	if (!m_navMesh)
		return 0.f;
	MT_Point3 localfrom = TransformToLocalCoords(from);
	MT_Point3 localto = TransformToLocalCoords(to);
	float spos[3], epos[3];
	localfrom.getValue(spos); flipAxes(spos);
	localto.getValue(epos); flipAxes(epos);
	dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt);
	float t=0;
	static dtStatPolyRef polys[MAX_PATH_LEN];
	m_navMesh->raycast(sPolyRef, spos, epos, t, polys, MAX_PATH_LEN);
	return t;
}
Beispiel #9
0
/**
 * Returns if points q is inside the circle defined by p1, p2 and p3.
 * @param p1 point
 * @param p2 point
 * @param p3 point
 * @param q point
 * @return true if p4 or p5 are inside the circle, false otherwise. If 
 * the circle does not exist (p1, p2 and p3 are collinears) returns true
 */
bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
						const MT_Point3& q)
{
	MT_Point3 center;

	// Compute circle center
	bool ok = BOP_getCircleCenter(p1,p2,p3,center);
	
	if (!ok) return true; // p1,p2 and p3 are collinears

	// Check if q is inside the circle
	MT_Scalar r = p1.distance(center);
	MT_Scalar d = q.distance(center);    
	return (BOP_comp(d,r) <= 0);
}
Beispiel #10
0
static bool filterObstacle(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObst,
							float levelHeight)
{
	//filter obstacles by type
	if ( (otherObst == activeObst) ||
		(otherObst->m_type==KX_OBSTACLE_NAV_MESH && otherObst->m_gameObj!=activeNavMeshObj)	)
		return false;

	//filter obstacles by position
	MT_Point3 p = nearestPointToObstacle(activeObst->m_pos, otherObst);
	if ( fabs(activeObst->m_pos.z() - p.z()) > levelHeight)
		return false;

	return true;
}
Beispiel #11
0
int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius)
{
	ExtractFrustumSphere();
	if (center.distance2(m_frustum_center) > (radius + m_frustum_radius)*(radius + m_frustum_radius))
		return OUTSIDE;

	unsigned int p;
	ExtractClipPlanes();
	NormalizeClipPlanes();
		
	MT_Scalar distance;
	int intersect = INSIDE;
	// distance:  <-------- OUTSIDE -----|----- INTERSECT -----0----- INTERSECT -----|----- INSIDE -------->
	//                                -radius                                      radius
	for (p = 0; p < 6; p++)
	{
		distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3];
		if (fabs(distance) <= radius)
			intersect = INTERSECT;
		else if (distance < -radius)
			return OUTSIDE;
	}
	
	return intersect;
}
Beispiel #12
0
void KX_KetsjiEngine::DoSound(KX_Scene* scene)
{
	m_logger->StartLog(tc_sound, m_kxsystem->GetTimeInSeconds(), true);

	KX_Camera* cam = scene->GetActiveCamera();
	if (!cam)
		return;
	MT_Point3 listenerposition = cam->NodeGetWorldPosition();
	MT_Vector3 listenervelocity = cam->GetLinearVelocity();
	MT_Matrix3x3 listenerorientation = cam->NodeGetWorldOrientation();

	{
		AUD_3DData data;
		float f;

		listenerorientation.getValue3x3(data.orientation);
		listenerposition.getValue(data.position);
		listenervelocity.getValue(data.velocity);

		f = data.position[1];
		data.position[1] = data.position[2];
		data.position[2] = -f;

		f = data.velocity[1];
		data.velocity[1] = data.velocity[2];
		data.velocity[2] = -f;

		f = data.orientation[1];
		data.orientation[1] = data.orientation[2];
		data.orientation[2] = -f;

		f = data.orientation[3];
		data.orientation[3] = -data.orientation[6];
		data.orientation[6] = f;

		f = data.orientation[4];
		data.orientation[4] = -data.orientation[8];
		data.orientation[8] = -f;

		f = data.orientation[5];
		data.orientation[5] = data.orientation[7];
		data.orientation[7] = f;

		AUD_updateListener(&data);
	}
}
Beispiel #13
0
RAS_TexVert::RAS_TexVert(const MT_Point3& xyz,
						 const MT_Point2& uv,
						 const MT_Point2& uv2,
						 const MT_Vector4& tangent,
						 const unsigned int rgba,
						 const MT_Vector3& normal,
						 const bool flat,
						 const unsigned int origindex)
{
	xyz.getValue(m_localxyz);
	uv.getValue(m_uv1);
	uv2.getValue(m_uv2);
	SetRGBA(rgba);
	SetNormal(normal);
	tangent.getValue(m_tangent);
	m_flag = (flat)? FLAT: 0;
	m_origindex = origindex;
	m_unit = 2;
	m_softBodyIndex = -1;
}
Beispiel #14
0
RAS_TexVert::RAS_TexVert(const MT_Point3& xyz,
						 const MT_Point2 uvs[MAX_UNIT],
						 const MT_Vector4& tangent,
						 const unsigned int rgba,
						 const MT_Vector3& normal,
						 const bool flat,
						 const unsigned int origindex)
{
	xyz.getValue(m_localxyz);
	SetRGBA(rgba);
	SetNormal(normal);
	tangent.getValue(m_tangent);
	m_flag = (flat)? FLAT: 0;
	m_origindex = origindex;
	m_unit = 2;
	m_softBodyIndex = -1;

	for (int i = 0; i < MAX_UNIT; ++i)
	{
		uvs[i].getValue(m_uvs[i]);
	}
}
Beispiel #15
0
void RAS_TexVert::SetXYZ(const MT_Point3& xyz)
{
	xyz.getValue(m_localxyz);
}
bool KX_SoundActuator::Update(double curtime, bool frame)
{
	if (!frame)
		return true;
	bool result = false;

	// do nothing on negative events, otherwise sounds are played twice!
	bool bNegativeEvent = IsNegativeEvent();
	bool bPositiveEvent = m_posevent;

	RemoveAllEvents();

	if (!m_sound)
		return false;

	// actual audio device playing state
	bool isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false;

	if (bNegativeEvent)
	{
		// here must be a check if it is still playing
		if (m_isplaying && isplaying)
		{
			switch (m_type)
			{
			case KX_SOUNDACT_PLAYSTOP:
			case KX_SOUNDACT_LOOPSTOP:
			case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
				{
					// stop immediately
					if (m_handle)
					{
						AUD_Handle_stop(m_handle);
						m_handle = NULL;
					}
					break;
				}
			case KX_SOUNDACT_PLAYEND:
				{
					// do nothing, sound will stop anyway when it's finished
					break;
				}
			case KX_SOUNDACT_LOOPEND:
			case KX_SOUNDACT_LOOPBIDIRECTIONAL:
				{
					// stop the looping so that the sound stops when it finished
					if (m_handle)
						AUD_Handle_setLoopCount(m_handle, 0);
					break;
				}
			default:
				// implement me !!
				break;
			}
		}
		// remember that we tried to stop the actuator
		m_isplaying = false;
	}

#if 1
	// Warning: when de-activating the actuator, after a single negative event this runs again with...
	// m_posevent==false && m_posevent==false, in this case IsNegativeEvent() returns false
	// and assumes this is a positive event.
	// check that we actually have a positive event so as not to play sounds when being disabled.
	else if (bPositiveEvent)  /* <- added since 2.49 */
#else
	else	// <- works in most cases except a loop-end sound will never stop unless
			// the negative pulse is done continuesly
#endif
	{
		if (!m_isplaying)
			play();
	}
	// verify that the sound is still playing
	isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false;

	if (isplaying)
	{
		if (m_is3d)
		{
			KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera();
			if (cam)
			{
				KX_GameObject* obj = (KX_GameObject*)this->GetParent();
				MT_Point3 p;
				MT_Matrix3x3 Mo;
				float data[4];

				Mo = cam->NodeGetWorldOrientation().inverse();
				p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition());
				p = Mo * p;
				p.getValue(data);
				AUD_Handle_setLocation(m_handle, data);
				p = (obj->GetLinearVelocity() - cam->GetLinearVelocity());
				p = Mo * p;
				p.getValue(data);
				AUD_Handle_setVelocity(m_handle, data);
				(Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(data);
				AUD_Handle_setOrientation(m_handle, data);
			}
		}
		result = true;
	}
	else
	{
		m_isplaying = false;
		result = false;
	}
	return result;
}
Beispiel #17
0
/**
 * Pre: p0, p1 and p2 is a triangle and q is an interior point.
 * @param p0 point
 * @param p1 point
 * @param p2 point
 * @param q point
 * @return intersection point I
 *                v 
 *  (p0)-----(I)----->(p1)
 *    \       ^        /
 *     \      |w      /
 *      \     |      /
 *       \   (q)    /
 *        \   |    /
 *         \  |   /
 *          \ |  /
 *           (p2)
 *
 * v = P1-P2
 * w = P3-Q
 * r0(t) = v*t+P1
 * r1(t) = w*t+P3
 * I = r0^r1
 */
MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, 
							  const MT_Point3& q)
{
	MT_Vector3 v(p0.x()-p1.x(), p0.y()-p1.y(), p0.z()-p1.z());
	MT_Vector3 w(p2.x()-q.x(), p2.y()-q.y(), p2.z()-q.z());
	MT_Point3 I;
	
	BOP_intersect(v,p0,w,p2,I);
	return I;
}
Beispiel #18
0
/**
 * Intersects a plane with the line that contains the specified points.
 * @param plane split plane
 * @param p1 first line point
 * @param p2 second line point
 * @return intersection between plane and line that contains p1 and p2
 */
MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2)
{
	// Compute intersection between plane and line ...
    //
	//       L: (p2-p1)lambda + p1
	//
	// supposes resolve equation ...
	//
	//       coefA*((p2.x - p1.y)*lambda + p1.x) + ... + coefD = 0
	
    MT_Point3 intersection = MT_Point3(0,0,0); //never ever return anything undefined! 
    MT_Scalar den = plane.x()*(p2.x()-p1.x()) + 
					plane.y()*(p2.y()-p1.y()) + 
					plane.z()*(p2.z()-p1.z());
	if (den != 0) {
		MT_Scalar lambda = (-plane.x()*p1.x()-plane.y()*p1.y()-plane.z()*p1.z()-plane.w()) / den;
		intersection.setValue(p1.x() + (p2.x()-p1.x())*lambda, 
						  p1.y() + (p2.y()-p1.y())*lambda, 
						  p1.z() + (p2.z()-p1.z())*lambda);
		return intersection;
	}
	return intersection;
}
Beispiel #19
0
bool BL_ShapeActionActuator::Update(double curtime, bool frame)
{
	bool bNegativeEvent = false;
	bool bPositiveEvent = false;
	bool keepgoing = true;
	bool wrap = false;
	bool apply=true;
	int	priority;
	float newweight;

	curtime -= KX_KetsjiEngine::GetSuspendedDelta();
	
	// result = true if animation has to be continued, false if animation stops
	// maybe there are events for us in the queue !
	if (frame)
	{
		bNegativeEvent = m_negevent;
		bPositiveEvent = m_posevent;
		RemoveAllEvents();
		
		if (bPositiveEvent)
			m_flag |= ACT_FLAG_ACTIVE;
		
		if (bNegativeEvent)
		{
			if (!(m_flag & ACT_FLAG_ACTIVE))
				return false;
			m_flag &= ~ACT_FLAG_ACTIVE;
		}
	}
	
	/*	This action can only be attached to a deform object */
	BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
	float length = m_endframe - m_startframe;
	
	priority = m_priority;
	
	/* Determine pre-incrementation behaviour and set appropriate flags */
	switch (m_playtype){
	case ACT_ACTION_MOTION:
		if (bNegativeEvent){
			keepgoing=false;
			apply=false;
		};
		break;
	case ACT_ACTION_FROM_PROP:
		if (bNegativeEvent){
			apply=false;
			keepgoing=false;
		}
		break;
	case ACT_ACTION_LOOP_END:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_KEYUP;
				m_flag &= ~ACT_FLAG_REVERSE;
				m_flag |= ACT_FLAG_LOCKINPUT;
				m_localtime = m_startframe;
				m_starttime = curtime;
			}
		}
		if (bNegativeEvent){
			m_flag |= ACT_FLAG_KEYUP;
		}
		break;
	case ACT_ACTION_LOOP_STOP:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_REVERSE;
				m_flag &= ~ACT_FLAG_KEYUP;
				m_flag |= ACT_FLAG_LOCKINPUT;
				SetStartTime(curtime);
			}
		}
		if (bNegativeEvent){
			m_flag |= ACT_FLAG_KEYUP;
			m_flag &= ~ACT_FLAG_LOCKINPUT;
			keepgoing=false;
			apply=false;
		}
		break;
	case ACT_ACTION_PINGPONG:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_KEYUP;
				m_localtime = m_starttime;
				m_starttime = curtime;
				m_flag |= ACT_FLAG_LOCKINPUT;
			}
		}
		break;
	case ACT_ACTION_FLIPPER:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_REVERSE;
				m_flag |= ACT_FLAG_LOCKINPUT;
				SetStartTime(curtime);
			}
		}
		else if (bNegativeEvent){
			m_flag |= ACT_FLAG_REVERSE;
			m_flag &= ~ACT_FLAG_LOCKINPUT;
			SetStartTime(curtime);
		}
		break;
	case ACT_ACTION_PLAY:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_REVERSE;
				m_localtime = m_starttime;
				m_starttime = curtime;
				m_flag |= ACT_FLAG_LOCKINPUT;
			}
		}
		break;
	default:
		break;
	}
	
	/* Perform increment */
	if (keepgoing){
		if (m_playtype == ACT_ACTION_MOTION){
			MT_Point3	newpos;
			MT_Point3	deltapos;
			
			newpos = obj->NodeGetWorldPosition();
			
			/* Find displacement */
			deltapos = newpos-m_lastpos;
			m_localtime += (length/m_stridelength) * deltapos.length();
			m_lastpos = newpos;
		}
		else{
			SetLocalTime(curtime);
		}
	}
	
	/* Check if a wrapping response is needed */
	if (length){
		if (m_localtime < m_startframe || m_localtime > m_endframe)
		{
			m_localtime = m_startframe + fmod(m_localtime, length);
			wrap = true;
		}
	}
	else
		m_localtime = m_startframe;
	
	/* Perform post-increment tasks */
	switch (m_playtype){
	case ACT_ACTION_FROM_PROP:
		{
			CValue* propval = GetParent()->GetProperty(m_propname);
			if (propval)
				m_localtime = propval->GetNumber();
			
			if (bNegativeEvent){
				keepgoing=false;
			}
		}
		break;
	case ACT_ACTION_MOTION:
		break;
	case ACT_ACTION_LOOP_STOP:
		break;
	case ACT_ACTION_PINGPONG:
		if (wrap){
			if (!(m_flag & ACT_FLAG_REVERSE))
				m_localtime = m_endframe;
			else 
				m_localtime = m_startframe;

			m_flag &= ~ACT_FLAG_LOCKINPUT;
			m_flag ^= ACT_FLAG_REVERSE; //flip direction
			keepgoing = false;
		}
		break;
	case ACT_ACTION_FLIPPER:
		if (wrap){
			if (!(m_flag & ACT_FLAG_REVERSE)){
				m_localtime=m_endframe;
				//keepgoing = false;
			}
			else {
				m_localtime=m_startframe;
				keepgoing = false;
			}
		}
		break;
	case ACT_ACTION_LOOP_END:
		if (wrap){
			if (m_flag & ACT_FLAG_KEYUP){
				keepgoing = false;
				m_localtime = m_endframe;
				m_flag &= ~ACT_FLAG_LOCKINPUT;
			}
			SetStartTime(curtime);
		}
		break;
	case ACT_ACTION_PLAY:
		if (wrap){
			m_localtime = m_endframe;
			keepgoing = false;
			m_flag &= ~ACT_FLAG_LOCKINPUT;
		}
		break;
	default:
		keepgoing = false;
		break;
	}
	
	/* Set the property if its defined */
	if (m_framepropname[0] != '\0') {
		CValue* propowner = GetParent();
		CValue* oldprop = propowner->GetProperty(m_framepropname);
		CValue* newval = new CFloatValue(m_localtime);
		if (oldprop) {
			oldprop->SetValue(newval);
		} else {
			propowner->SetProperty(m_framepropname, newval);
		}
		newval->Release();
	}
	
	if (bNegativeEvent)
		m_blendframe=0.0f;
	
	/* Apply the pose if necessary*/
	if (apply) {

		/* Priority test */
		if (obj->SetActiveAction(this, priority, curtime)){
			BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
			Key *key = NULL;

			if (shape_deformer)
				key = shape_deformer->GetKey();

			if (!key) {
				// this could happen if the mesh was changed in the middle of an action
				// and the new mesh has no key, stop the action
				keepgoing = false;
			}
			else {
				ListBase tchanbase= {NULL, NULL};
			
				if (m_blendin && m_blendframe==0.0f){
					// this is the start of the blending, remember the startup shape
					obj->GetShape(m_blendshape);
					m_blendstart = curtime;
				}

				KeyBlock *kb;
				// We go through and clear out the keyblocks so there isn't any interference
				// from other shape actions
				for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
					kb->curval = 0.f;

				animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime);

				// XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell
				if (0) { // XXX !execute_ipochannels(&tchanbase)) {
					// no update, this is possible if action does not match the keys, stop the action
					keepgoing = false;
				} 
				else {
					// the key have changed, apply blending if needed
					if (m_blendin && (m_blendframe<m_blendin)){
						newweight = (m_blendframe/(float)m_blendin);

						BlendShape(key, 1.0f - newweight);

						/* Increment current blending percentage */
						m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
						if (m_blendframe>m_blendin)
							m_blendframe = m_blendin;
					}
					m_lastUpdate = m_localtime;
				}
				BLI_freelistN(&tchanbase);
			}
		}
		else{
			m_blendframe = 0.0f;
		}
	}
	
	if (!keepgoing){
		m_blendframe = 0.0f;
	}
	return keepgoing;
};
Beispiel #20
0
void ImageRender::Render()
{
    RAS_FrameFrustum frustrum;

    if (!m_render)
        return;

    if (m_mirror)
    {
        // mirror mode, compute camera frustrum, position and orientation
        // convert mirror position and normal in world space
        const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation();
        const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition();
        const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling();
        MT_Point3 mirrorWorldPos =
            mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos);
        MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ;
        // get observer world position
        const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition();
        // get plane D term = mirrorPos . normal
        MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ);
        // compute distance of observer to mirror = D - observerPos . normal
        MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ);
        // if distance < 0.01 => observer is on wrong side of mirror, don't render
        if (observerDistance < 0.01)
            return;
        // set camera world position = observerPos + normal * 2 * distance
        MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ;
        m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos);
        // set camera orientation: z=normal, y=mirror_up in world space, x= y x z
        MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY;
        MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX;
        MT_Matrix3x3 cameraWorldOri(
            mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0],
            mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1],
            mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]);
        m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri);
        m_camera->GetSGNode()->UpdateWorldData(0.0);
        // compute camera frustrum:
        //   get position of mirror relative to camera: offset = mirrorPos-cameraPos
        MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos;
        //   convert to camera orientation
        mirrorOffset = mirrorOffset * cameraWorldOri;
        //   scale mirror size to world scale:
        //     get closest local axis for mirror Y and X axis and scale height and width by local axis scale
        MT_Scalar x, y;
        x = fabs(m_mirrorY[0]);
        y = fabs(m_mirrorY[1]);
        float height = (x > y) ?
                       ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
                       ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
        x = fabs(m_mirrorX[0]);
        y = fabs(m_mirrorX[1]);
        float width = (x > y) ?
                      ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
                      ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
        width *= m_mirrorHalfWidth;
        height *= m_mirrorHalfHeight;
        //   left = offsetx-width
        //   right = offsetx+width
        //   top = offsety+height
        //   bottom = offsety-height
        //   near = -offsetz
        //   far = near+100
        frustrum.x1 = mirrorOffset[0]-width;
        frustrum.x2 = mirrorOffset[0]+width;
        frustrum.y1 = mirrorOffset[1]-height;
        frustrum.y2 = mirrorOffset[1]+height;
        frustrum.camnear = -mirrorOffset[2];
        frustrum.camfar = -mirrorOffset[2]+m_clip;
    }
    // Store settings to be restored later
    const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
    RAS_Rect area = m_canvas->GetWindowArea();

    // The screen area that ImageViewport will copy is also the rendering zone
    m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
    m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
    m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
    m_rasterizer->BeginFrame(m_engine->GetClockTime());
    m_scene->GetWorldInfo()->UpdateWorldSettings();
    m_rasterizer->SetAuxilaryClientInfo(m_scene);
    m_rasterizer->DisplayFog();
    // matrix calculation, don't apply any of the stereo mode
    m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO);
    if (m_mirror)
    {
        // frustrum was computed above
        // get frustrum matrix and set projection matrix
        MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
                                   frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);

        m_camera->SetProjectionMatrix(projmat);
    }
    else if (m_camera->hasValidProjectionMatrix()) {
        m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix());
    }
    else {
        float lens = m_camera->GetLens();
        float sensor_x = m_camera->GetSensorWidth();
        float sensor_y = m_camera->GetSensorHeight();
        float shift_x = m_camera->GetShiftHorizontal();
        float shift_y = m_camera->GetShiftVertical();
        bool orthographic = !m_camera->GetCameraData()->m_perspective;
        float nearfrust = m_camera->GetCameraNear();
        float farfrust = m_camera->GetCameraFar();
        float aspect_ratio = 1.0f;
        Scene *blenderScene = m_scene->GetBlenderScene();
        MT_Matrix4x4 projmat;

        // compute the aspect ratio from frame blender scene settings so that render to texture
        // works the same in Blender and in Blender player
        if (blenderScene->r.ysch != 0)
            aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp);

        if (orthographic) {

            RAS_FramingManager::ComputeDefaultOrtho(
                nearfrust,
                farfrust,
                m_camera->GetScale(),
                aspect_ratio,
                m_camera->GetSensorFit(),
                shift_x,
                shift_y,
                frustrum
            );

            projmat = m_rasterizer->GetOrthoMatrix(
                          frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
        }
        else {
            RAS_FramingManager::ComputeDefaultFrustum(
                nearfrust,
                farfrust,
                lens,
                sensor_x,
                sensor_y,
                RAS_SENSORFIT_AUTO,
                shift_x,
                shift_y,
                aspect_ratio,
                frustrum);

            projmat = m_rasterizer->GetFrustumMatrix(
                          frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
        }
        m_camera->SetProjectionMatrix(projmat);
    }

    MT_Transform camtrans(m_camera->GetWorldToCamera());
    MT_Matrix4x4 viewmat(camtrans);

    m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective);
    m_camera->SetModelviewMatrix(viewmat);
    // restore the stereo mode now that the matrix is computed
    m_rasterizer->SetStereoMode(stereomode);

    if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) {
        // In QUAD buffer stereo mode, the GE render pass ends with the right eye on the right buffer
        // but we need to draw on the left buffer to capture the render
        // TODO: implement an explicit function in rasterizer to restore the left buffer.
        m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
    }

    m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);

    m_engine->UpdateAnimations(m_scene);

    m_scene->RenderBuckets(camtrans, m_rasterizer);

    m_scene->RenderFonts();

    // restore the canvas area now that the render is completed
    m_canvas->GetWindowArea() = area;
}
Beispiel #21
0
/**
 * Computes the intersection between two lines (on the same plane).
 * @param vL1 first line vector
 * @param pL1 first line point
 * @param vL2 second line vector
 * @param pL2 second line point
 * @param intersection intersection point (if exists)
 * @return false if lines are parallels, true otherwise
 */
bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, 
				   const MT_Point3& pL2, MT_Point3 &intersection)
{
	// NOTE: 
    // If the lines aren't on the same plane, the intersection point will not be valid. 
	// So be careful !!

	MT_Scalar t = -1;
	MT_Scalar den = (vL1.y()*vL2.x() - vL1.x() * vL2.y());
	
	if (!BOP_fuzzyZero(den)) {
		t =  (pL2.y()*vL1.x() - vL1.y()*pL2.x() + pL1.x()*vL1.y() - pL1.y()*vL1.x()) / den ;
	}
	else {
		den = (vL1.y()*vL2.z() - vL1.z() * vL2.y());
		if (!BOP_fuzzyZero(den)) {
			t =  (pL2.y()*vL1.z() - vL1.y()*pL2.z() + pL1.z()*vL1.y() - pL1.y()*vL1.z()) / den ;
		}
		else {
			den = (vL1.x()*vL2.z() - vL1.z() * vL2.x());
			if (!BOP_fuzzyZero(den)) {
				t =  (pL2.x()*vL1.z() - vL1.x()*pL2.z() + pL1.z()*vL1.x() - pL1.x()*vL1.z()) / den ;
			}
			else {
				return false;
			}
		}
	}
	
	intersection.setValue(vL2.x()*t + pL2.x(), vL2.y()*t + pL2.y(), vL2.z()*t + pL2.z());
	return true;
}
Beispiel #22
0
/**
 * Returns if p1 is between p2 and p3 and lay on the same line (are collinears).
 * @param p1 point
 * @param p2 point
 * @param p3 point
 * @return true if p1 is between p2 and p3 and lay on the same line, false otherwise
 */
bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3)
{
	MT_Scalar distance = p2.distance(p3);
	return (p1.distance(p2) < distance && p1.distance(p3) < distance) && BOP_collinear(p1,p2,p3);
}
Beispiel #23
0
void KX_Camera::ExtractFrustumSphere()
{
	if (m_set_frustum_center)
		return;

	// compute sphere for the general case and not only symmetric frustum:
	// the mirror code in ImageRender can use very asymmetric frustum.
	// We will put the sphere center on the line that goes from origin to the center of the far clipping plane
	// This is the optimal position if the frustum is symmetric or very asymmetric and probably close
	// to optimal for the general case. The sphere center position is computed so that the distance to
	// the near and far extreme frustum points are equal.

	// get the transformation matrix from device coordinate to camera coordinate
	MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix;
	clip_camcs_matrix.invert();

	if (m_projection_matrix[3][3] == MT_Scalar(0.0))
	{
		// frustrum projection
		// detect which of the corner of the far clipping plane is the farthest to the origin
		MT_Vector4 nfar;    // far point in device normalized coordinate
		MT_Point3 farpoint; // most extreme far point in camera coordinate
		MT_Point3 nearpoint;// most extreme near point in camera coordinate
		MT_Point3 farcenter(0.0, 0.0, 0.0);// center of far cliping plane in camera coordinate
		MT_Scalar F=-1.0, N; // square distance of far and near point to origin
		MT_Scalar f, n;     // distance of far and near point to z axis. f is always > 0 but n can be < 0
		MT_Scalar e, s;     // far and near clipping distance (<0)
		MT_Scalar c;        // slope of center line = distance of far clipping center to z axis / far clipping distance
		MT_Scalar z;        // projection of sphere center on z axis (<0)
		// tmp value
		MT_Vector4 npoint(1.0, 1.0, 1.0, 1.0);
		MT_Vector4 hpoint;
		MT_Point3 point;
		MT_Scalar len;
		for (int i=0; i<4; i++)
		{
			hpoint = clip_camcs_matrix*npoint;
			point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]);
			len = point.dot(point);
			if (len > F)
			{
				nfar = npoint;
				farpoint = point;
				F = len;
			}
			// rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane
			len = npoint[0];
			npoint[0] = -npoint[1];
			npoint[1] = len;
			farcenter += point;
		}
		// the far center is the average of the far clipping points
		farcenter *= 0.25;
		// the extreme near point is the opposite point on the near clipping plane
		nfar.setValue(-nfar[0], -nfar[1], -1.0, 1.0);
		nfar = clip_camcs_matrix*nfar;
		nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]);
		// this is a frustrum projection
		N = nearpoint.dot(nearpoint);
		e = farpoint[2];
		s = nearpoint[2];
		// projection on XY plane for distance to axis computation
		MT_Point2 farxy(farpoint[0], farpoint[1]);
		// f is forced positive by construction
		f = farxy.length();
		// get corresponding point on the near plane
		farxy *= s/e;
		// this formula preserve the sign of n
		n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length();
		c = MT_Point2(farcenter[0], farcenter[1]).length()/e;
		// the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case
		z = (F-N)/(2.0*(e-s+c*(f-n)));
		m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z);
		m_frustum_radius = m_frustum_center.distance(farpoint);
	}
	else
	{
		// orthographic projection
		// The most extreme points on the near and far plane. (normalized device coords)
		MT_Vector4 hnear(1.0, 1.0, 1.0, 1.0), hfar(-1.0, -1.0, -1.0, 1.0);
		
		// Transform to hom camera local space
		hnear = clip_camcs_matrix*hnear;
		hfar = clip_camcs_matrix*hfar;
		
		// Tranform to 3d camera local space.
		MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]);
		MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]);
		
		// just use mediant point
		m_frustum_center = (farpoint + nearpoint)*0.5;
		m_frustum_radius = m_frustum_center.distance(farpoint);
	}
	// Transform to world space.
	m_frustum_center = GetCameraToWorld()(m_frustum_center);
	m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
	
	m_set_frustum_center = true;
}
void KX_BulletPhysicsController::setPosition(const MT_Point3& pos)
{
	CcdPhysicsController::setPosition(pos.x(),pos.y(),pos.z());
}
Beispiel #25
0
bool BL_ActionActuator::Update(double curtime, bool frame)
{
	bool bNegativeEvent = false;
	bool bPositiveEvent = false;
	bool keepgoing = true;
	bool wrap = false;
	bool apply=true;
	int	priority;
	float newweight;

	curtime -= KX_KetsjiEngine::GetSuspendedDelta();
	
	// result = true if animation has to be continued, false if animation stops
	// maybe there are events for us in the queue !
	if (frame)
	{
		bNegativeEvent = m_negevent;
		bPositiveEvent = m_posevent;
		RemoveAllEvents();
		
		if (bPositiveEvent)
			m_flag |= ACT_FLAG_ACTIVE;
		
		if (bNegativeEvent)
		{
			// dont continue where we left off when restarting
			if (m_end_reset) {
				m_flag &= ~ACT_FLAG_LOCKINPUT;
			}
			
			if (!(m_flag & ACT_FLAG_ACTIVE))
				return false;
			m_flag &= ~ACT_FLAG_ACTIVE;
		}
	}
	
	/*	We know that action actuators have been discarded from all non armature objects:
	if we're being called, we're attached to a BL_ArmatureObject */
	BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
	float length = m_endframe - m_startframe;
	
	priority = m_priority;
	
	/* Determine pre-incrementation behaviour and set appropriate flags */
	switch (m_playtype){
	case ACT_ACTION_MOTION:
		if (bNegativeEvent){
			keepgoing=false;
			apply=false;
		};
		break;
	case ACT_ACTION_FROM_PROP:
		if (bNegativeEvent){
			apply=false;
			keepgoing=false;
		}
		break;
	case ACT_ACTION_LOOP_END:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_KEYUP;
				m_flag &= ~ACT_FLAG_REVERSE;
				m_flag |= ACT_FLAG_LOCKINPUT;
				m_localtime = m_startframe;
				m_starttime = curtime;
			}
		}
		if (bNegativeEvent){
			m_flag |= ACT_FLAG_KEYUP;
		}
		break;
	case ACT_ACTION_LOOP_STOP:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_REVERSE;
				m_flag &= ~ACT_FLAG_KEYUP;
				m_flag |= ACT_FLAG_LOCKINPUT;
				SetStartTime(curtime);
			}
		}
		if (bNegativeEvent){
			m_flag |= ACT_FLAG_KEYUP;
			m_flag &= ~ACT_FLAG_LOCKINPUT;
			keepgoing=false;
			apply=false;
		}
		break;
	case ACT_ACTION_FLIPPER:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_REVERSE;
				m_flag |= ACT_FLAG_LOCKINPUT;
				SetStartTime(curtime);
			}
		}
		else if (bNegativeEvent){
			m_flag |= ACT_FLAG_REVERSE;
			m_flag &= ~ACT_FLAG_LOCKINPUT;
			SetStartTime(curtime);
		}
		break;
	case ACT_ACTION_PLAY:
		if (bPositiveEvent){
			if (!(m_flag & ACT_FLAG_LOCKINPUT)){
				m_flag &= ~ACT_FLAG_REVERSE;
				m_localtime = m_starttime;
				m_starttime = curtime;
				m_flag |= ACT_FLAG_LOCKINPUT;
			}
		}
		break;
	default:
		break;
	}
	
	/* Perform increment */
	if (keepgoing){
		if (m_playtype == ACT_ACTION_MOTION){
			MT_Point3	newpos;
			MT_Point3	deltapos;
			
			newpos = obj->NodeGetWorldPosition();
			
			/* Find displacement */
			deltapos = newpos-m_lastpos;
			m_localtime += (length/m_stridelength) * deltapos.length();
			m_lastpos = newpos;
		}
		else{
			SetLocalTime(curtime);
		}
	}
	
	/* Check if a wrapping response is needed */
	if (length){
		if (m_localtime < m_startframe || m_localtime > m_endframe)
		{
			m_localtime = m_startframe + fmod(m_localtime, length);
			wrap = true;
		}
	}
	else
		m_localtime = m_startframe;
	
	/* Perform post-increment tasks */
	switch (m_playtype){
	case ACT_ACTION_FROM_PROP:
		{
			CValue* propval = GetParent()->GetProperty(m_propname);
			if (propval)
				m_localtime = propval->GetNumber();
			
			if (bNegativeEvent){
				keepgoing=false;
			}
		}
		break;
	case ACT_ACTION_MOTION:
		break;
	case ACT_ACTION_LOOP_STOP:
		break;
	case ACT_ACTION_FLIPPER:
		if (wrap){
			if (!(m_flag & ACT_FLAG_REVERSE)){
				m_localtime=m_endframe;
				//keepgoing = false;
			}
			else {
				m_localtime=m_startframe;
				keepgoing = false;
			}
		}
		break;
	case ACT_ACTION_LOOP_END:
		if (wrap){
			if (m_flag & ACT_FLAG_KEYUP){
				keepgoing = false;
				m_localtime = m_endframe;
				m_flag &= ~ACT_FLAG_LOCKINPUT;
			}
			SetStartTime(curtime);
		}
		break;
	case ACT_ACTION_PLAY:
		if (wrap){
			m_localtime = m_endframe;
			keepgoing = false;
			m_flag &= ~ACT_FLAG_LOCKINPUT;
		}
		break;
	default:
		keepgoing = false;
		break;
	}
	
	/* Set the property if its defined */
	if (m_framepropname[0] != '\0') {
		CValue* propowner = GetParent();
		CValue* oldprop = propowner->GetProperty(m_framepropname);
		CValue* newval = new CFloatValue(m_localtime);
		if (oldprop) {
			oldprop->SetValue(newval);
		} else {
			propowner->SetProperty(m_framepropname, newval);
		}
		newval->Release();
	}
	
	if (bNegativeEvent)
		m_blendframe=0.0;
	
	/* Apply the pose if necessary*/
	if (apply){

		/* Priority test */
		if (obj->SetActiveAction(this, priority, curtime)){
			
			/* Get the underlying pose from the armature */
			obj->GetPose(&m_pose);

// 2.4x function, 
			/* Override the necessary channels with ones from the action */
			// XXX extract_pose_from_action(m_pose, m_action, m_localtime);
			
			
// 2.5x - replacement for extract_pose_from_action(...) above.
			{
				struct PointerRNA id_ptr;
				Object *arm= obj->GetArmatureObject();
				bPose *pose_back= arm->pose;
				
				arm->pose= m_pose;
				RNA_id_pointer_create((ID *)arm, &id_ptr);
				animsys_evaluate_action(&id_ptr, m_action, NULL, m_localtime);
				
				arm->pose= pose_back;
			
// 2.5x - could also do this but looks too high level, constraints use this, it works ok.
//				Object workob; /* evaluate using workob */
//				what_does_obaction((Scene *)obj->GetScene(), obj->GetArmatureObject(), &workob, m_pose, m_action, NULL, m_localtime);
			}

			// done getting the pose from the action
			
			/* Perform the user override (if any) */
			if (m_userpose){
				extract_pose_from_pose(m_pose, m_userpose);
				game_free_pose(m_userpose); //cant use MEM_freeN(m_userpose) because the channels need freeing too.
				m_userpose = NULL;
			}
#if 1
			/* Handle blending */
			if (m_blendin && (m_blendframe<m_blendin)){
				/* If this is the start of a blending sequence... */
				if ((m_blendframe==0.0) || (!m_blendpose)){
					obj->GetMRDPose(&m_blendpose);
					m_blendstart = curtime;
				}
				
				/* Find percentages */
				newweight = (m_blendframe/(float)m_blendin);
				game_blend_poses(m_pose, m_blendpose, 1.0 - newweight);

				/* Increment current blending percentage */
				m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
				if (m_blendframe>m_blendin)
					m_blendframe = m_blendin;
				
			}
#endif
			m_lastUpdate = m_localtime;
			obj->SetPose (m_pose);
		}
		else{
			m_blendframe = 0.0;
		}
	}
	
	if (!keepgoing){
		m_blendframe = 0.0;
	}
	return keepgoing;
};