bool KX_WorldIpoController::Update(double currentTime)
{
	if (m_modified) {
		T_InterpolatorList::iterator i;
		for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
			(*i)->Execute(m_ipotime);
		}

		KX_WorldInfo *world = KX_GetActiveScene()->GetWorldInfo();

		if (m_modify_mist_start) {
			world->setMistStart(m_mist_start);
		}

		if (m_modify_mist_dist) {
			world->setMistDistance(m_mist_dist);
		}

		if (m_modify_mist_intensity) {
			world->setMistIntensity(m_mist_intensity);
		}

		if (m_modify_horizon_color) {
			world->setBackColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]);
			world->setMistColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]);
		}

		if (m_modify_ambient_color) {
			world->setAmbientColor(m_ambi_rgb[0], m_ambi_rgb[1], m_ambi_rgb[2]);
		}

		m_modified = false;
	}
	return false;
}
void KX_NavMeshObject::ProcessReplica()
{
	KX_GameObject::ProcessReplica();
	m_navMesh = NULL;  /* without this, building frees the navmesh we copied from */
	BuildNavMesh();
	KX_Scene* scene = KX_GetActiveScene();
	KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation();
	if (obssimulation)
		obssimulation->AddObstaclesForNavMesh(this);

}
Exemple #3
0
void KX_NavMeshObject::ProcessReplica()
{
	KX_GameObject::ProcessReplica();

	BuildNavMesh();
	KX_Scene* scene = KX_GetActiveScene();
	KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation();
	if (obssimulation)
		obssimulation->AddObstaclesForNavMesh(this);

}
PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
{

	PyObject *pylistPos,*pylistDir,*pylistAxleDir;
	PyObject *wheelGameObject;
	float suspensionRestLength,wheelRadius;
	int hasSteering;


	if (PyArg_ParseTuple(args,"OOOOffi:addWheel",&wheelGameObject,&pylistPos,&pylistDir,&pylistAxleDir,&suspensionRestLength,&wheelRadius,&hasSteering))
	{
		KX_GameObject *gameOb;
		if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)"))
			return NULL;

		if (gameOb->GetSGNode())
		{
			MT_Vector3 attachPos,attachDir,attachAxle;
			if (!PyVecTo(pylistPos,attachPos)) {
				PyErr_SetString(PyExc_AttributeError,
				                "addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements.");
				return NULL;
			}
			if (!PyVecTo(pylistDir,attachDir))  {
				PyErr_SetString(PyExc_AttributeError,
				                "addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements.");
				return NULL;
			}
			if (!PyVecTo(pylistAxleDir,attachAxle)) {
				PyErr_SetString(PyExc_AttributeError,
				                "addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements.");
				return NULL;
			}

			//someone reverse some conventions inside Bullet (axle winding)
			attachAxle = -attachAxle;

			if (wheelRadius <= 0) {
				PyErr_SetString(PyExc_AttributeError,
				                "addWheel(...) Unable to add wheel. wheelRadius must be positive.");
				return NULL;
			}

			PHY_IMotionState *motionState = new KX_MotionState(gameOb->GetSGNode());
			m_vehicle->AddWheel(motionState,attachPos,attachDir,attachAxle,suspensionRestLength,wheelRadius,hasSteering);
		}

	} else {
		return NULL;
	}
	Py_RETURN_NONE;
}
bool KX_ParentActuator::Update()
{
	bool bNegativeEvent = IsNegativeEvent();
	RemoveAllEvents();

	if (bNegativeEvent)
		return false; // do nothing on negative events

	KX_GameObject *obj = (KX_GameObject*) GetParent();
	KX_Scene *scene = KX_GetActiveScene();
	switch (m_mode) {
		case KX_PARENT_SET:
			if (m_ob)
				obj->SetParent(scene, (KX_GameObject*)m_ob, m_addToCompound, m_ghost);
			break;
		case KX_PARENT_REMOVE:
			obj->RemoveParent(scene);
			break;
	};
	
	return false;
}
Exemple #6
0
bool KX_SoundActuator::Update(double curtime, bool frame)
{
	if (!frame)
		return true;
	bool result = false;

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

#ifdef WITH_AUDASPACE
	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_Vector3 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;
	}
#endif  // WITH_AUDASPACE

	return result;
}
bool BL_Action::Play(const char* name,
					float start,
					float end,
					short priority,
					float blendin,
					short play_mode,
					float layer_weight,
					short ipo_flags,
					float playback_speed)
{

	// Only start playing a new action if we're done, or if
	// the new action has a higher priority
	if (!IsDone() && priority > m_priority)
		return false;
	m_priority = priority;
	bAction* prev_action = m_action;

	// First try to load the action
	m_action = (bAction*)KX_GetActiveScene()->GetLogicManager()->GetActionByName(name);
	if (!m_action)
	{
		printf("Failed to load action: %s\n", name);
		m_done = true;
		return false;
	}

	// If we have the same settings, don't play again
	// This is to resolve potential issues with pulses on sensors such as the ones
	// reported in bug #29412. The fix is here so it works for both logic bricks and Python.
	// However, this may eventually lead to issues where a user wants to override an already
	// playing action with the same action and settings. If this becomes an issue,
	// then this fix may have to be re-evaluated.
	if (!IsDone() && m_action == prev_action && m_startframe == start && m_endframe == end
			&& m_priority == priority && m_speed == playback_speed)
		return false;

	if (prev_action != m_action)
	{
		// First get rid of any old controllers
		ClearControllerList();

		// Create an SG_Controller
		SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
		m_sg_contr_list.push_back(sg_contr);
		m_obj->GetSGNode()->AddSGController(sg_contr);
		sg_contr->SetObject(m_obj->GetSGNode());

		// Extra controllers
		if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT)
		{
			sg_contr = BL_CreateLampIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
			m_sg_contr_list.push_back(sg_contr);
			m_obj->GetSGNode()->AddSGController(sg_contr);
			sg_contr->SetObject(m_obj->GetSGNode());
		}
		else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA)
		{
			sg_contr = BL_CreateCameraIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
			m_sg_contr_list.push_back(sg_contr);
			m_obj->GetSGNode()->AddSGController(sg_contr);
			sg_contr->SetObject(m_obj->GetSGNode());
		}
	}
	
	m_ipo_flags = ipo_flags;
	InitIPO();

	// Setup blendin shapes/poses
	if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
	{
		BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
		obj->GetMRDPose(&m_blendinpose);
	}
	else
	{
		BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
		BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
		
		if (shape_deformer && shape_deformer->GetKey())
		{
			obj->GetShape(m_blendinshape);

			// Now that we have the previous blend shape saved, we can clear out the key to avoid any
			// further interference.
			KeyBlock *kb;
			for (kb=(KeyBlock*)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock*)kb->next)
				kb->curval = 0.f;
		}
	}

	// Now that we have an action, we have something we can play
	m_starttime = -1.f; // We get the start time on our first update
	m_startframe = m_localtime = start;
	m_endframe = end;
	m_blendin = blendin;
	m_playmode = play_mode;
	m_endtime = 0.f;
	m_blendframe = 0.f;
	m_blendstart = 0.f;
	m_speed = playback_speed;
	m_layer_weight = layer_weight;
	
	m_done = false;

	return true;
}
bool KX_ConstraintActuator::Update(double curtime, bool frame)
{

	bool result = false;
	bool bNegativeEvent = IsNegativeEvent();
	RemoveAllEvents();

	if (!bNegativeEvent) {
		/* Constraint clamps the values to the specified range, with a sort of    */
		/* low-pass filtered time response, if the damp time is unequal to 0.     */

		/* Having to retrieve location/rotation and setting it afterwards may not */
		/* be efficient enough... Something to look at later.                     */
		KX_GameObject  *obj = (KX_GameObject*) GetParent();
		MT_Vector3    position = obj->NodeGetWorldPosition();
		MT_Vector3    newposition;
		MT_Vector3   normal, direction, refDirection;
		MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
		MT_Scalar    filter, newdistance, cosangle;
		int axis, sign;

		if (m_posDampTime) {
			filter = m_posDampTime/(1.0f+m_posDampTime);
		} else {
			filter = 0.0f;
		}
		switch (m_locrot) {
		case KX_ACT_CONSTRAINT_ORIX:
		case KX_ACT_CONSTRAINT_ORIY:
		case KX_ACT_CONSTRAINT_ORIZ:
			switch (m_locrot) {
			case KX_ACT_CONSTRAINT_ORIX:
				direction[0] = rotation[0][0];
				direction[1] = rotation[1][0];
				direction[2] = rotation[2][0];
				axis = 0;
				break;
			case KX_ACT_CONSTRAINT_ORIY:
				direction[0] = rotation[0][1];
				direction[1] = rotation[1][1];
				direction[2] = rotation[2][1];
				axis = 1;
				break;
			default:
				direction[0] = rotation[0][2];
				direction[1] = rotation[1][2];
				direction[2] = rotation[2][2];
				axis = 2;
				break;
			}
			if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
				// reference direction needs to be evaluated
				// 1. get the cosine between current direction and target
				cosangle = direction.dot(m_refDirVector);
				if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
					// no change to do
					result = true;
					goto CHECK_TIME;
				}
				// 2. define a new reference direction
				//    compute local axis with reference direction as X and
				//    Y in direction X refDirection plane
				MT_Vector3 zaxis = m_refDirVector.cross(direction);
				if (MT_fuzzyZero2(zaxis.length2())) {
					// direction and refDirection are identical,
					// choose any other direction to define plane
					if (direction[0] < 0.9999f)
						zaxis = m_refDirVector.cross(MT_Vector3(1.0f,0.0f,0.0f));
					else
						zaxis = m_refDirVector.cross(MT_Vector3(0.0f,1.0f,0.0f));
				}
				MT_Vector3 yaxis = zaxis.cross(m_refDirVector);
				yaxis.normalize();
				if (cosangle > m_minimumBound) {
					// angle is too close to reference direction,
					// choose a new reference that is exactly at minimum angle
					refDirection = m_minimumBound * m_refDirVector + m_minimumSine * yaxis;
				} else {
					// angle is too large, choose new reference direction at maximum angle
					refDirection = m_maximumBound * m_refDirVector + m_maximumSine * yaxis;
				}
			} else {
				refDirection = m_refDirVector;
			}
			// apply damping on the direction
			direction = filter*direction + (1.0f-filter)*refDirection;
			obj->AlignAxisToVect(direction, axis);
			result = true;
			goto CHECK_TIME;
		case KX_ACT_CONSTRAINT_DIRPX:
		case KX_ACT_CONSTRAINT_DIRPY:
		case KX_ACT_CONSTRAINT_DIRPZ:
		case KX_ACT_CONSTRAINT_DIRNX:
		case KX_ACT_CONSTRAINT_DIRNY:
		case KX_ACT_CONSTRAINT_DIRNZ:
			switch (m_locrot) {
			case KX_ACT_CONSTRAINT_DIRPX:
				normal[0] = rotation[0][0];
				normal[1] = rotation[1][0];
				normal[2] = rotation[2][0];
				axis = 0;		// axis according to KX_GameObject::AlignAxisToVect()
				sign = 0;		// X axis will be parrallel to direction of ray
				break;
			case KX_ACT_CONSTRAINT_DIRPY:
				normal[0] = rotation[0][1];
				normal[1] = rotation[1][1];
				normal[2] = rotation[2][1];
				axis = 1;
				sign = 0;
				break;
			case KX_ACT_CONSTRAINT_DIRPZ:
				normal[0] = rotation[0][2];
				normal[1] = rotation[1][2];
				normal[2] = rotation[2][2];
				axis = 2;
				sign = 0;
				break;
			case KX_ACT_CONSTRAINT_DIRNX:
				normal[0] = -rotation[0][0];
				normal[1] = -rotation[1][0];
				normal[2] = -rotation[2][0];
				axis = 0;
				sign = 1;
				break;
			case KX_ACT_CONSTRAINT_DIRNY:
				normal[0] = -rotation[0][1];
				normal[1] = -rotation[1][1];
				normal[2] = -rotation[2][1];
				axis = 1;
				sign = 1;
				break;
			case KX_ACT_CONSTRAINT_DIRNZ:
				normal[0] = -rotation[0][2];
				normal[1] = -rotation[1][2];
				normal[2] = -rotation[2][2];
				axis = 2;
				sign = 1;
				break;
			}
			normal.normalize();
			if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
				// direction of the ray is along the local axis
				direction = normal;
			} else {
				switch (m_locrot) {
				case KX_ACT_CONSTRAINT_DIRPX:
					direction = MT_Vector3(1.0f,0.0f,0.0f);
					break;
				case KX_ACT_CONSTRAINT_DIRPY:
					direction = MT_Vector3(0.0f,1.0f,0.0f);
					break;
				case KX_ACT_CONSTRAINT_DIRPZ:
					direction = MT_Vector3(0.0f,0.0f,1.0f);
					break;
				case KX_ACT_CONSTRAINT_DIRNX:
					direction = MT_Vector3(-1.0f,0.0f,0.0f);
					break;
				case KX_ACT_CONSTRAINT_DIRNY:
					direction = MT_Vector3(0.0f,-1.0f,0.0f);
					break;
				case KX_ACT_CONSTRAINT_DIRNZ:
					direction = MT_Vector3(0.0f,0.0f,-1.0f);
					break;
				}
			}
			{
				MT_Vector3 topoint = position + (m_maximumBound) * direction;
				PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment();
				PHY_IPhysicsController *spc = obj->GetPhysicsController();

				if (!pe) {
					CM_LogicBrickWarning(this, "there is no physics environment!");
					goto CHECK_TIME;
				}	 
				if (!spc) {
					// the object is not physical, we probably want to avoid hitting its own parent
					KX_GameObject *parent = obj->GetParent();
					if (parent) {
						spc = parent->GetPhysicsController();
					}
				}
				KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this,dynamic_cast<PHY_IPhysicsController*>(spc));
				result = KX_RayCast::RayTest(pe, position, topoint, callback);
				if (result)	{
					MT_Vector3 newnormal = callback.m_hitNormal;
					// compute new position & orientation
					if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
						// if none option is set, the actuator does nothing but detect ray 
						// (works like a sensor)
						goto CHECK_TIME;
					}
					if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
						MT_Scalar rotFilter;
						// apply damping on the direction
						if (m_rotDampTime) {
							rotFilter = m_rotDampTime/(1.0f+m_rotDampTime);
						} else {
							rotFilter = filter;
						}
						newnormal = rotFilter*normal - (1.0f-rotFilter)*newnormal;
						obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
						if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
							direction = newnormal;
							direction.normalize();
						}
					}
					if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
						if (m_posDampTime) {
							newdistance = filter*(position-callback.m_hitPoint).length()+(1.0f-filter)*m_minimumBound;
						} else {
							newdistance = m_minimumBound;
						}
						// logically we should cancel the speed along the ray direction as we set the
						// position along that axis
						spc = obj->GetPhysicsController();
						if (spc && spc->IsDynamic()) {
							MT_Vector3 linV = spc->GetLinearVelocity();
							// cancel the projection along the ray direction
							MT_Scalar fallspeed = linV.dot(direction);
							if (!MT_fuzzyZero(fallspeed))
								spc->SetLinearVelocity(linV-fallspeed*direction,false);
						}
					} else {
						newdistance = (position-callback.m_hitPoint).length();
					}
					newposition = callback.m_hitPoint-newdistance*direction;
				} else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
					// no contact but still keep running
					result = true;
					goto CHECK_TIME;
				}
			}
			break; 
		case KX_ACT_CONSTRAINT_FHPX:
		case KX_ACT_CONSTRAINT_FHPY:
		case KX_ACT_CONSTRAINT_FHPZ:
		case KX_ACT_CONSTRAINT_FHNX:
		case KX_ACT_CONSTRAINT_FHNY:
		case KX_ACT_CONSTRAINT_FHNZ:
			switch (m_locrot) {
			case KX_ACT_CONSTRAINT_FHPX:
				normal[0] = -rotation[0][0];
				normal[1] = -rotation[1][0];
				normal[2] = -rotation[2][0];
				direction = MT_Vector3(1.0f,0.0f,0.0f);
				break;
			case KX_ACT_CONSTRAINT_FHPY:
				normal[0] = -rotation[0][1];
				normal[1] = -rotation[1][1];
				normal[2] = -rotation[2][1];
				direction = MT_Vector3(0.0f,1.0f,0.0f);
				break;
			case KX_ACT_CONSTRAINT_FHPZ:
				normal[0] = -rotation[0][2];
				normal[1] = -rotation[1][2];
				normal[2] = -rotation[2][2];
				direction = MT_Vector3(0.0f,0.0f,1.0f);
				break;
			case KX_ACT_CONSTRAINT_FHNX:
				normal[0] = rotation[0][0];
				normal[1] = rotation[1][0];
				normal[2] = rotation[2][0];
				direction = MT_Vector3(-1.0f,0.0f,0.0f);
				break;
			case KX_ACT_CONSTRAINT_FHNY:
				normal[0] = rotation[0][1];
				normal[1] = rotation[1][1];
				normal[2] = rotation[2][1];
				direction = MT_Vector3(0.0f,-1.0f,0.0f);
				break;
			case KX_ACT_CONSTRAINT_FHNZ:
				normal[0] = rotation[0][2];
				normal[1] = rotation[1][2];
				normal[2] = rotation[2][2];
				direction = MT_Vector3(0.0f,0.0f,-1.0f);
				break;
			}
			normal.normalize();
			{
				PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment();
				PHY_IPhysicsController *spc = obj->GetPhysicsController();

				if (!pe) {
					CM_LogicBrickWarning(this, "there is no physics environment!");
					goto CHECK_TIME;
				}	 
				if (!spc || !spc->IsDynamic()) {
					// the object is not dynamic, it won't support setting speed
					goto CHECK_TIME;
				}
				m_hitObject = NULL;
				// distance of Fh area is stored in m_minimum
				MT_Vector3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
				KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this, spc);
				result = KX_RayCast::RayTest(pe, position, topoint, callback);
				// we expect a hit object
				if (!m_hitObject)
					result = false;
				if (result)
				{
					MT_Vector3 newnormal = callback.m_hitNormal;
					// compute new position & orientation
					MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius(); 
					// estimate the velocity of the hit point
					MT_Vector3 relativeHitPoint;
					relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition());
					MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint);
					MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint;
					MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity);
					MT_Scalar springExtent = 1.0f - distance/m_minimumBound;
					// Fh force is stored in m_maximum
					MT_Scalar springForce = springExtent * m_maximumBound;
					// damping is stored in m_refDirection [0] = damping, [1] = rot damping
					MT_Scalar springDamp = relativeVelocityRay * m_refDirVector[0];
					MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction;
					if (m_option & KX_ACT_CONSTRAINT_NORMAL)
					{
						newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction);
					}
					spc->SetLinearVelocity(newVelocity, false);
					if (m_option & KX_ACT_CONSTRAINT_DOROTFH)
					{
						MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound;
						MT_Vector3 angVelocity = spc->GetAngularVelocity();
						// remove component that is parallel to normal
						angVelocity -= angVelocity.dot(newnormal)*newnormal;
						MT_Vector3 angDamp = angVelocity * ((m_refDirVector[1]>MT_EPSILON)?m_refDirVector[1]:m_refDirVector[0]);
						spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false);
					}
				} else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
					// no contact but still keep running
					result = true;
				}
				// don't set the position with this constraint
				goto CHECK_TIME;
			}
			break; 
		case KX_ACT_CONSTRAINT_LOCX:
		case KX_ACT_CONSTRAINT_LOCY:
		case KX_ACT_CONSTRAINT_LOCZ:
			newposition = position = obj->GetSGNode()->GetLocalPosition();
			switch (m_locrot) {
			case KX_ACT_CONSTRAINT_LOCX:
				Clamp(newposition[0], m_minimumBound, m_maximumBound);
				break;
			case KX_ACT_CONSTRAINT_LOCY:
				Clamp(newposition[1], m_minimumBound, m_maximumBound);
				break;
			case KX_ACT_CONSTRAINT_LOCZ:
				Clamp(newposition[2], m_minimumBound, m_maximumBound);
				break;
			}
			result = true;
			if (m_posDampTime) {
				newposition = filter*position + (1.0f-filter)*newposition;
			}
			obj->NodeSetLocalPosition(newposition);
			goto CHECK_TIME;
		}
		if (result) {
			// set the new position but take into account parent if any
			obj->NodeSetWorldPosition(newposition);
		}
	CHECK_TIME:
		if (result && m_activeTime > 0 ) {
			if (++m_currentTime >= m_activeTime)
				result = false;
		}
	}
	if (!result) {
		m_currentTime = 0;
	}
	return result;
} /* end of KX_ConstraintActuator::Update(double curtime,double deltatime)   */
Exemple #9
0
bool BL_Action::Play(const char* name,
					float start,
					float end,
					short priority,
					float blendin,
					short play_mode,
					float layer_weight,
					short ipo_flags,
					float playback_speed)
{

	// Only start playing a new action if we're done, or if
	// the new action has a higher priority
	if (priority != 0 && !IsDone() && priority >= m_priority)
		return false;
	m_priority = priority;
	bAction* prev_action = m_action;

	// First try to load the action
	m_action = (bAction*)KX_GetActiveScene()->GetLogicManager()->GetActionByName(name);
	if (!m_action)
	{
		printf("Failed to load action: %s\n", name);
		m_done = true;
		return false;
	}

	if (prev_action != m_action)
	{
		// First get rid of any old controllers
		ClearControllerList();

		// Create an SG_Controller
		SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
		m_sg_contr_list.push_back(sg_contr);
		m_obj->GetSGNode()->AddSGController(sg_contr);
		sg_contr->SetObject(m_obj->GetSGNode());

		// Extra controllers
		if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT)
		{
			sg_contr = BL_CreateLampIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
			m_sg_contr_list.push_back(sg_contr);
			m_obj->GetSGNode()->AddSGController(sg_contr);
			sg_contr->SetObject(m_obj->GetSGNode());
		}
		else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA)
		{
			sg_contr = BL_CreateCameraIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter());
			m_sg_contr_list.push_back(sg_contr);
			m_obj->GetSGNode()->AddSGController(sg_contr);
			sg_contr->SetObject(m_obj->GetSGNode());
		}
	}
	
	m_ipo_flags = ipo_flags;
	InitIPO();

	// Setup blendin shapes/poses
	if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
	{
		BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
		obj->GetMRDPose(&m_blendinpose);
	}
	else
	{
		BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj;
		BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
		
		if (shape_deformer && shape_deformer->GetKey())
		{
			obj->GetShape(m_blendinshape);

			// Now that we have the previous blend shape saved, we can clear out the key to avoid any
			// further interference.
			KeyBlock *kb;
			for (kb=(KeyBlock*)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock*)kb->next)
				kb->curval = 0.f;
		}
	}

	// Now that we have an action, we have something we can play
	m_starttime = KX_GetActiveEngine()->GetFrameTime();
	m_startframe = m_localtime = start;
	m_endframe = end;
	m_blendin = blendin;
	m_playmode = play_mode;
	m_endtime = 0.f;
	m_blendframe = 0.f;
	m_blendstart = 0.f;
	m_speed = playback_speed;
	m_layer_weight = layer_weight;
	
	m_done = false;

	return true;
}
Exemple #10
0
bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts,
									   unsigned short* &polys, int& npolys, unsigned short *&dmeshes,
									   float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, 
									   int& ndtris, int &vertsPerPoly)
{
	DerivedMesh* dm = mesh_create_derived_no_virtual(KX_GetActiveScene()->GetBlenderScene(), GetBlenderObject(), 
													NULL, CD_MASK_MESH);
	int* recastData = (int*) dm->getFaceDataArray(dm, CD_RECAST);
	if (recastData)
	{
		int *dtrisToPolysMap=NULL, *dtrisToTrisMap=NULL, *trisToFacesMap=NULL;
		int nAllVerts = 0;
		float *allVerts = NULL;
		buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nAllVerts, &allVerts, &ndtris, &dtris,
			&npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap, &trisToFacesMap);

		MEM_freeN(dtrisToPolysMap);
		MEM_freeN(dtrisToTrisMap);
		MEM_freeN(trisToFacesMap);

		unsigned short *verticesMap = new unsigned short[nAllVerts];
		memset(verticesMap, 0xffff, sizeof(unsigned short)*nAllVerts);
		int curIdx = 0;
		//vertices - mesh verts
		//iterate over all polys and create map for their vertices first...
		for (int polyidx=0; polyidx<npolys; polyidx++)
		{
			unsigned short* poly = &polys[polyidx*vertsPerPoly*2];
			for (int i=0; i<vertsPerPoly; i++)
			{
				unsigned short idx = poly[i];
				if (idx==0xffff)
					break;
				if (verticesMap[idx]==0xffff)
				{
					verticesMap[idx] = curIdx++;
				}
				poly[i] = verticesMap[idx];
			}
		}
		nverts = curIdx;
		//...then iterate over detailed meshes
		//transform indices to local ones (for each navigation polygon)
		for (int polyidx=0; polyidx<npolys; polyidx++)
		{
			unsigned short *poly = &polys[polyidx*vertsPerPoly*2];
			int nv = polyNumVerts(poly, vertsPerPoly);
			unsigned short *dmesh = &dmeshes[4*polyidx];
			unsigned short tribase = dmesh[2];
			unsigned short trinum = dmesh[3];
			unsigned short vbase = curIdx;
			for (int j=0; j<trinum; j++)
			{
				unsigned short* dtri = &dtris[(tribase+j)*3*2];
				for (int k=0; k<3; k++)
				{
					int newVertexIdx = verticesMap[dtri[k]];
					if (newVertexIdx==0xffff)
					{
						newVertexIdx = curIdx++;
						verticesMap[dtri[k]] = newVertexIdx;
					}

					if (newVertexIdx<nverts)
					{
						//it's polygon vertex ("shared")
						int idxInPoly = polyFindVertex(poly, vertsPerPoly, newVertexIdx);
						if (idxInPoly==-1)
						{
							printf("Building NavMeshObject: Error! Can't find vertex in polygon\n");
							return false;
						}
						dtri[k] = idxInPoly;
					}
					else
					{
						dtri[k] = newVertexIdx - vbase + nv;
					}
				}
			}
			dmesh[0] = vbase-nverts; //verts base
			dmesh[1] = curIdx-vbase; //verts num
		}

		vertices = new float[nverts*3];
		ndvertsuniq = curIdx - nverts;
		if (ndvertsuniq>0)
		{
			dvertices = new float[ndvertsuniq*3];
		}
		for (int vi=0; vi<nAllVerts; vi++)
		{
			int newIdx = verticesMap[vi];
			if (newIdx!=0xffff)
			{
				if (newIdx<nverts)
				{
					//navigation mesh vertex
					memcpy(vertices+3*newIdx, allVerts+3*vi, 3*sizeof(float));
				}
				else
				{
					//detailed mesh vertex
					memcpy(dvertices+3*(newIdx-nverts), allVerts+3*vi, 3*sizeof(float));
				}				
			}
		}

		MEM_freeN(allVerts);
	}
	else
	{
		//create from RAS_MeshObject (detailed mesh is fake)
		RAS_MeshObject* meshobj = GetMesh(0);
		vertsPerPoly = 3;
		nverts = meshobj->m_sharedvertex_map.size();
		if (nverts >= 0xffff)
			return false;
		//calculate count of tris
		int nmeshpolys = meshobj->NumPolygons();
		npolys = nmeshpolys;
		for (int p=0; p<nmeshpolys; p++)
		{
			int vertcount = meshobj->GetPolygon(p)->VertexCount();
			npolys+=vertcount-3;
		}

		//create verts
		vertices = new float[nverts*3];
		float* vert = vertices;
		for (int vi=0; vi<nverts; vi++)
		{
			const float* pos = !meshobj->m_sharedvertex_map[vi].empty() ? meshobj->GetVertexLocation(vi) : NULL;
			if (pos)
				copy_v3_v3(vert, pos);
			else
			{
				memset(vert, 0, 3*sizeof(float)); //vertex isn't in any poly, set dummy zero coordinates
			}
			vert+=3;		
		}

		//create tris
		polys = new unsigned short[npolys*3*2];
		memset(polys, 0xff, sizeof(unsigned short)*3*2*npolys);
		unsigned short *poly = polys;
		RAS_Polygon* raspoly;
		for (int p=0; p<nmeshpolys; p++)
		{
			raspoly = meshobj->GetPolygon(p);
			for (int v=0; v<raspoly->VertexCount()-2; v++)
			{
				poly[0]= raspoly->GetVertex(0)->getOrigIndex();
				for (size_t i=1; i<3; i++)
				{
					poly[i]= raspoly->GetVertex(v+i)->getOrigIndex();
				}
				poly += 6;
			}
		}
		dmeshes = NULL;
		dvertices = NULL;
		ndvertsuniq = 0;
		dtris = NULL;
		ndtris = npolys;
	}
	dm->release(dm);
	
	return true;
}
void KX_FontObject::ProcessReplica()
{
    KX_GameObject::ProcessReplica();
    KX_GetActiveScene()->AddFont(this);
}
Exemple #12
0
bool KX_KetsjiEngine::NextFrame()
{
	double timestep = 1.0/m_ticrate;
	double framestep = timestep;
//	static hidden::Clock sClock;

m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true);

//float dt = sClock.getTimeMicroseconds() * 0.000001f;
//sClock.reset();

if (m_bFixedTime)
	m_clockTime += timestep;
else
{

//	m_clockTime += dt;
	m_clockTime = m_kxsystem->GetTimeInSeconds();
}
	
	double deltatime = m_clockTime - m_frameTime;
	if (deltatime<0.f)
	{
		printf("problem with clock\n");
		deltatime = 0.f;
		m_clockTime = 0.f;
		m_frameTime = 0.f;
	}


	// Compute the number of logic frames to do each update (fixed tic bricks)
	int frames =int(deltatime*m_ticrate+1e-6);
//	if (frames>1)
//		printf("****************************************");
//	printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
	
//	if (!frames)
//		PIL_sleep_ms(1);
	
	KX_SceneList::iterator sceneit;
	
	if (frames>m_maxPhysicsFrame)
	{
	
	//	printf("framedOut: %d\n",frames);
		m_frameTime+=(frames-m_maxPhysicsFrame)*timestep;
		frames = m_maxPhysicsFrame;
	}
	

	bool doRender = frames>0;

	if (frames > m_maxLogicFrame)
	{
		framestep = (frames*timestep)/m_maxLogicFrame;
		frames = m_maxLogicFrame;
	}

	while (frames)
	{
	

		m_frameTime += framestep;
		
		for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
		// for each scene, call the proceed functions
		{
			KX_Scene* scene = *sceneit;
	
			/* Suspension holds the physics and logic processing for an
			* entire scene. Objects can be suspended individually, and
			* the settings for that preceed the logic and physics
			* update. */
			m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);

			m_sceneconverter->resetNoneDynamicObjectToIpo();//this is for none dynamic objects with ipo

			scene->UpdateObjectActivity();
	
			if (!scene->IsSuspended())
			{
				// if the scene was suspended recalcutlate the delta tu "curtime"
				m_suspendedtime = scene->getSuspendedTime();
				if (scene->getSuspendedTime()!=0.0)
					scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
				m_suspendeddelta = scene->getSuspendedDelta();

				
				m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_NETWORK);
				scene->GetNetworkScene()->proceed(m_frameTime);
	
				//m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				//SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE);
				//scene->UpdateParents(m_frameTime);
				
				m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_PHYSICS1);
				// set Python hooks for each scene
#ifdef WITH_PYTHON
				PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
#endif
				KX_SetActiveScene(scene);
	
				scene->GetPhysicsEnvironment()->endFrame();
				
				// Update scenegraph after physics step. This maps physics calculations
				// into node positions.		
				//m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				//SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE);
				//scene->UpdateParents(m_frameTime);
				
				// Process sensors, and controllers
				m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_CONTROLLER);
				scene->LogicBeginFrame(m_frameTime);
	
				// Scenegraph needs to be updated again, because Logic Controllers 
				// can affect the local matrices.
				m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE);
				scene->UpdateParents(m_frameTime);
	
				// Process actuators
	
				// Do some cleanup work for this logic frame
				m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_ACTUATOR);
				scene->LogicUpdateFrame(m_frameTime, true);
				
				scene->LogicEndFrame();
	
				// Actuators can affect the scenegraph
				m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE);
				scene->UpdateParents(m_frameTime);

				if (!GetRestrictAnimationFPS())
				{
					m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
					SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
					scene->UpdateAnimations(m_frameTime);
				}

				m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_PHYSICS2);
				scene->GetPhysicsEnvironment()->beginFrame();
		
				// Perform physics calculations on the scene. This can involve 
				// many iterations of the physics solver.
				scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,timestep,framestep);//m_deltatimerealDeltaTime);

				m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE);
				scene->UpdateParents(m_frameTime);
			
			
				if (m_animation_record)
				{					
					m_sceneconverter->WritePhysicsObjectToAnimationIpo(++m_currentFrame);
				}

				scene->setSuspendedTime(0.0);
			} // suspended
			else
				if(scene->getSuspendedTime()==0.0)
					scene->setSuspendedTime(m_clockTime);
			
			m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
		}

		// update system devices
		m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
		if (m_keyboarddevice)
			m_keyboarddevice->NextFrame();
	
		if (m_mousedevice)
			m_mousedevice->NextFrame();
		
		if (m_networkdevice)
			m_networkdevice->NextFrame();

		// scene management
		ProcessScheduledScenes();
		
		frames--;
	}

	bool bUseAsyncLogicBricks= false;//true;

	if (bUseAsyncLogicBricks)
	{	
		// Logic update sub frame: this will let some logic bricks run at the
		// full frame rate.
		for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
		// for each scene, call the proceed functions
		{
			KX_Scene* scene = *sceneit;

			if (!scene->IsSuspended())
			{
				// if the scene was suspended recalcutlate the delta tu "curtime"
				m_suspendedtime = scene->getSuspendedTime();
				if (scene->getSuspendedTime()!=0.0)
					scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
				m_suspendeddelta = scene->getSuspendedDelta();
				
				// set Python hooks for each scene
#ifdef WITH_PYTHON
				PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
#endif
				KX_SetActiveScene(scene);
				
				m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_PHYSICS1);
				scene->UpdateParents(m_clockTime);

				// Perform physics calculations on the scene. This can involve 
				// many iterations of the physics solver.
				m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
				scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,timestep,timestep);
				// Update scenegraph after physics step. This maps physics calculations
				// into node positions.		
				m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_PHYSICS2);
				scene->UpdateParents(m_clockTime);
				
				// Do some cleanup work for this logic frame
				m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
				scene->LogicUpdateFrame(m_clockTime, false);

				// Actuators can affect the scenegraph
				m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
				SG_SetActiveStage(SG_STAGE_ACTUATOR);
				scene->UpdateParents(m_clockTime);

				scene->setSuspendedTime(0.0);
			} // suspended
			else
				if(scene->getSuspendedTime()==0.0)
					scene->setSuspendedTime(m_clockTime);

			m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
		}
	}

		
	// Handle the animations independently of the logic time step
	if (GetRestrictAnimationFPS())
	{
		m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
		SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);

		double anim_timestep = 1.0/KX_GetActiveScene()->GetAnimationFPS();
		if (m_clockTime - m_previousAnimTime > anim_timestep)
		{
			// Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep)
			// printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime));
			m_previousAnimTime = m_clockTime;
			for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
			{
				(*sceneit)->UpdateAnimations(m_frameTime);
			}
		}
		m_previousClockTime = m_clockTime;
	}
	
	// Start logging time spend outside main loop
	m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
	
	return doRender;
}
int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
	BL_ArmatureConstraint* self = static_cast<BL_ArmatureConstraint*>(self_v);
	bConstraint* constraint = self->m_constraint;
	bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
	int attr_order = attrdef-Attributes;
	int ival;
	double dval;
//	char* sval;
	SCA_LogicManager *logicmgr = KX_GetActiveScene()->GetLogicManager();
	KX_GameObject *oval;

	if (!constraint) {
		PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
		return PY_SET_ATTR_FAIL;
	}

	switch (attr_order) {
	case BCA_ENFORCE:
		dval = PyFloat_AsDouble(value);
		if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */
			PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1");
			return PY_SET_ATTR_FAIL;
		}
		constraint->enforce = dval;
		return PY_SET_ATTR_SUCCESS;

	case BCA_HEADTAIL:
		dval = PyFloat_AsDouble(value);
		if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */
			PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1");
			return PY_SET_ATTR_FAIL;
		}
		constraint->headtail = dval;
		return PY_SET_ATTR_SUCCESS;

	case BCA_TARGET:
		if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.target = value: BL_ArmatureConstraint"))
			return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
		self->SetTarget(oval);
		return PY_SET_ATTR_SUCCESS;

	case BCA_SUBTARGET:
		if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint"))
			return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
		self->SetSubtarget(oval);
		return PY_SET_ATTR_SUCCESS;

	case BCA_ACTIVE:
		ival = PyObject_IsTrue( value );
		if (ival == -1) {
			PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False");
			return PY_SET_ATTR_FAIL;
		}
		self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF);
		return PY_SET_ATTR_SUCCESS;

	case BCA_IKWEIGHT:
	case BCA_IKDIST:
	case BCA_IKMODE:
		if (!ikconstraint) {
			PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
			return PY_SET_ATTR_FAIL;
		}
		switch (attr_order) {
		case BCA_IKWEIGHT:
			dval = PyFloat_AsDouble(value);
			if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */
				PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1");
				return PY_SET_ATTR_FAIL;
			}
			ikconstraint->weight = dval;
			return PY_SET_ATTR_SUCCESS;

		case BCA_IKDIST:
			dval = PyFloat_AsDouble(value);
			if (dval < 0.0) {  /* also accounts for non float */
				PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float");
				return PY_SET_ATTR_FAIL;
			}
			ikconstraint->dist = dval;
			return PY_SET_ATTR_SUCCESS;

		case BCA_IKMODE:
			ival = PyLong_AsLong(value);
			if (ival < 0) {
				PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer");
				return PY_SET_ATTR_FAIL;
			}
			ikconstraint->mode = ival;
			return PY_SET_ATTR_SUCCESS;
		}
		// should not come here
		break;

	}

	PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
	return PY_SET_ATTR_FAIL;
}