コード例 #1
0
ファイル: PhysicsComponent.cpp プロジェクト: CZdravko/Horde
void PhysicsComponent::loadFromXml(const XMLNode* description) {
	GameLog::logMessage("LOADING BULLET FROM XML");
	// Delete old physics representation
	//release();

	Matrix4f objTrans;
	m_owner->executeEvent(&GameEvent(GameEvent::E_TRANSFORMATION, &GameEventData((float*) objTrans.x, 16), this));

	Vec3f t, r, s;
	objTrans.decompose(t, r, s);

	// Parse Physics Node Configuration
	float mass = static_cast<float>(atof(description->getAttribute("mass", "0.0")));

	const char* shape = description->getAttribute("shape", "Box");
	// create collision shape based on the node configuration
	if (shape && _stricmp(shape, "Box") == 0) // Bounding Box Shape
			{
		float dimX = static_cast<float>(atof(description->getAttribute("x", "1.0")));
		float dimY = static_cast<float>(atof(description->getAttribute("y", "1.0")));
		float dimZ = static_cast<float>(atof(description->getAttribute("z", "1.0")));
		// update box settings with node scaling (TODO is this necessary if we already set the scale by using setLocalScaling?)
		//m_collisionShape = new btBoxShape(btVector3(dimX * s.x, dimY * s.y, dimZ * s.z));
		m_collisionShape = new btBoxShape(btVector3(dimX, dimY, dimZ));
	} else if (shape && _stricmp(shape, "Sphere") == 0) // Sphere Shape
			{
		float radius = static_cast<float>(atof(description->getAttribute("radius", "1.0")));
		m_collisionShape = new btSphereShape(radius);
	} else if (shape && _stricmp(shape, "Cylinder") == 0) // Cylinder Shape
			{
		float radius0 = static_cast<float>(atof(description->getAttribute("radius", "1.0")));
		float height = static_cast<float>(atof(description->getAttribute("height", "1.0")));
		m_collisionShape = new btCylinderShape(btVector3(radius0, height, radius0));
	} else // Mesh Shape
	{
		MeshData meshData;
		GameEvent meshEvent(GameEvent::E_MESH_DATA, &meshData, this);
		// get mesh data from graphics engine
		m_owner->executeEvent(&meshEvent);

		if (meshData.VertexBase && (meshData.TriangleBase32 || meshData.TriangleBase16)) {
			// Create new mesh in physics engine
			m_btTriangleMesh = new btTriangleMesh();
			int offset = 3;
			if (meshData.TriangleMode == 5) // Triangle Strip
				offset = 1;

			// copy mesh from graphics to physics
			bool index16 = false;
			if (meshData.TriangleBase16)
				index16 = true;
			for (unsigned int i = 0; i < meshData.NumTriangleIndices - 2; i += offset) {
				unsigned int index1 = index16 ? (meshData.TriangleBase16[i] - meshData.VertRStart) * 3 : (meshData.TriangleBase32[i] - meshData.VertRStart) * 3;
				unsigned int index2 = index16 ? (meshData.TriangleBase16[i + 1] - meshData.VertRStart) * 3 : (meshData.TriangleBase32[i + 1] - meshData.VertRStart) * 3;
				unsigned int index3 = index16 ? (meshData.TriangleBase16[i + 2] - meshData.VertRStart) * 3 : (meshData.TriangleBase32[i + 2] - meshData.VertRStart) * 3;
				m_btTriangleMesh->addTriangle(btVector3(meshData.VertexBase[index1], meshData.VertexBase[index1 + 1], meshData.VertexBase[index1 + 2]),
						btVector3(meshData.VertexBase[index2], meshData.VertexBase[index2 + 1], meshData.VertexBase[index2 + 2]),
						btVector3(meshData.VertexBase[index3], meshData.VertexBase[index3 + 1], meshData.VertexBase[index3 + 2]));
			}

			bool useQuantizedAabbCompression = true;

			if (mass > 0) {
				//btGImpactMeshShape* shape = new btGImpactMeshShape(m_btTriangleMesh);

				btGImpactConvexDecompositionShape* shape = new btGImpactConvexDecompositionShape(m_btTriangleMesh, btVector3(1.f, 1.f, 1.f), btScalar(0.1f), true);

				shape->updateBound();

				//btCollisionDispatcher* dispatcher = static_cast<btCollisionDispatcher *>(Physics::instance()->dispatcher());
				//btGImpactCollisionAlgorithm::registerAlgorithm(dispatcher);

				m_collisionShape = shape;

				//m_collisionShape = new btConvexTriangleMeshShape(m_btTriangleMesh);
			} else
				// BvhTriangleMesh can be used only for static objects
				m_collisionShape = new btBvhTriangleMeshShape(m_btTriangleMesh, useQuantizedAabbCompression);
		} else {
			GameLog::errorMessage("The mesh data for the physics representation couldn't be retrieved");
			return;
		}
	}

	GameLog::logMessage("PARSED SHAPE FROM XML");

	bool kinematic = _stricmp(description->getAttribute("kinematic", "false"), "true") == 0 || _stricmp(description->getAttribute("kinematic", "0"), "1") == 0;

	bool nondynamic = _stricmp(description->getAttribute("static", "false"), "true") == 0 || _stricmp(description->getAttribute("static", "0"), "1") == 0;

	bool ragdoll = _stricmp(description->getAttribute("ragdoll", "false"), "true") == 0 || _stricmp(description->getAttribute("ragdoll", "0"), "1") == 0;
	// Create initial transformation without scale
	btTransform tr;
	tr.setIdentity();
	tr.setRotation(btQuaternion(r.x, r.y, r.z));

	btMatrix3x3 rot = tr.getBasis();

	XMLNode offsetXMLNode = description->getChildNode("Offset");

	if (!offsetXMLNode.isEmpty()) {
		lX = static_cast<float>(atof(offsetXMLNode.getAttribute("lX", "0.0")));
		lY = static_cast<float>(atof(offsetXMLNode.getAttribute("lY", "0.0")));
		lZ = static_cast<float>(atof(offsetXMLNode.getAttribute("lZ", "0.0")));
	}

	btVector3 offset = btVector3(lX * s.x, lY * s.y, lZ * s.z);

	tr.setOrigin(btVector3(t.x, t.y, t.z) + rot * offset);
	// Set local scaling in collision shape because Bullet does not support scaling in the world transformation matrices
	m_collisionShape->setLocalScaling(btVector3(s.x, s.y, s.z));
	btVector3 localInertia(0, 0, 0);
	//rigidbody is dynamic if and only if mass is non zero otherwise static
	if (mass != 0)
		m_collisionShape->calculateLocalInertia(mass, localInertia);
	if (mass != 0 || kinematic)
		//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
		m_motionState = new btDefaultMotionState(tr);

	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, m_motionState, m_collisionShape, localInertia);
	rbInfo.m_startWorldTransform = tr;
	//rbInfo.m_restitution = btScalar( atof(description->getAttribute("restitution", "0")) );
	//rbInfo.m_friction = btScalar( atof(description->getAttribute("static_friction", "0.5")) );
	// Threshold for deactivation of objects (if movement is below this value the object gets deactivated)
	//rbInfo.m_angularSleepingThreshold = 0.8f;
	//rbInfo.m_linearSleepingThreshold = 0.8f;

	m_rigidBody = new btRigidBody(rbInfo);
	m_rigidBody->setUserPointer(this);
	m_rigidBody->setDeactivationTime(2.0f);

	// Add support for collision detection if mass is zero but kinematic is explicitly enabled
	if (kinematic && mass == 0 && !nondynamic) {
		m_rigidBody->setCollisionFlags(m_rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
		m_rigidBody->setActivationState(DISABLE_DEACTIVATION);
	}
	if (nondynamic && mass == 0) {
		m_rigidBody->setCollisionFlags(m_rigidBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
	}

	bool isTrigger = _stricmp(description->getAttribute("solid", "true"), "false") == 0 || _stricmp(description->getAttribute("solid", "1"), "0") == 0;
	if (isTrigger) {
		setCollisionResponse(true);
	}

	GameLog::logMessage("I'm a new Physics body: %s my Motion state: %d", m_owner->id().c_str(), m_motionState);
	printf("I'm a new Physics body: %s my Motion state: %d\n", m_owner->id().c_str(), m_motionState);

	if(!ragdoll) Physics::instance()->addObject(this);

	/*Geometry Proxy*/
	XMLNode proxyXMLNode = description->getChildNode("Proxy");
	if (proxyXMLNode.isEmpty())
		return;

	m_proxy = GameModules::gameWorld()->entity(proxyXMLNode.getAttribute("name", ""));

	if (m_proxy) {
		m_proxy->addListener(GameEvent::E_SET_TRANSFORMATION, this);
		m_proxy->addListener(GameEvent::E_SET_TRANSLATION, this);
		m_proxy->addListener(GameEvent::E_SET_ROTATION, this);
		m_proxy->addListener(GameEvent::E_TRANSLATE_LOCAL, this);
		m_proxy->addListener(GameEvent::E_TRANSLATE_GLOBAL, this);
		m_proxy->addListener(GameEvent::E_ROTATE_LOCAL, this);
	} else
		printf("No PROXY FOUND with EntityID: %s\n", proxyXMLNode.getAttribute("name", ""));

	/*Adding constraints*/

	XMLNode constraintXMLNode = description->getChildNode("Constraint");
	if (constraintXMLNode.isEmpty())
		return;

	const char* constraintType = constraintXMLNode.getAttribute("type", "Hinge");
	const char* parentName = constraintXMLNode.getAttribute("parent", "");
	PhysicsComponent* parent = getParent(parentName);

	if (!parent) {
		printf("NO PARENT FOUND\n");
		return;
	}

	XMLNode transformXMLNode = constraintXMLNode.getChildNode("TransformA");
	float qX = static_cast<float>(atof(transformXMLNode.getAttribute("qx", "1.0")));
	float qY = static_cast<float>(atof(transformXMLNode.getAttribute("qy", "1.0")));
	float qZ = static_cast<float>(atof(transformXMLNode.getAttribute("qz", "1.0")));
	float qW = static_cast<float>(atof(transformXMLNode.getAttribute("qw", "1.0")));
	float vX = static_cast<float>(atof(transformXMLNode.getAttribute("vx", "1.0")));
	float vY = static_cast<float>(atof(transformXMLNode.getAttribute("vy", "1.0")));
	float vZ = static_cast<float>(atof(transformXMLNode.getAttribute("vz", "1.0")));
	btTransform transformA;
	transformA.setIdentity();
	printf("%f \t %f \t %f  \n ", qX, qY, qZ);
	transformA.getBasis().setEulerZYX(qZ, qY, qX);
//	transformA.getBasis().setEulerZYX(M_PI_2,0,0);
	transformA.setOrigin(btVector3(vX * s.x, vY * s.y, vZ * s.z));
//	printf("%f \t %f \t %f \t %s \n ", vX*s.x, vY*s.y, vZ*s.z, m_owner ? m_owner->id().c_str() : "no name");
//	btTransform transformA = btTransform(btQuaternion(qX, qY, qZ, qW), btVector3(vX*s.x, vY*s.y, vZ*s.z));

	transformXMLNode = constraintXMLNode.getChildNode("TransformB");
	qX = static_cast<float>(atof(transformXMLNode.getAttribute("qx", "1.0")));
	qY = static_cast<float>(atof(transformXMLNode.getAttribute("qy", "1.0")));
	qZ = static_cast<float>(atof(transformXMLNode.getAttribute("qz", "1.0")));
	qW = static_cast<float>(atof(transformXMLNode.getAttribute("qw", "1.0")));
	vX = static_cast<float>(atof(transformXMLNode.getAttribute("vx", "1.0")));
	vY = static_cast<float>(atof(transformXMLNode.getAttribute("vy", "1.0")));
	vZ = static_cast<float>(atof(transformXMLNode.getAttribute("vz", "1.0")));
//	btTransform transformB = btTransform(btQuaternion(qX, qY, qZ, qW), btVector3(vX*s.x, vY*s.y, vZ*s.z));
	btTransform transformB;
	transformB.setIdentity();
	transformB.getBasis().setEulerZYX(qZ, qY, qX);
//	transformB.getBasis().setEulerZYX(M_PI_2,0,0);
	transformB.setOrigin(btVector3(vX * s.x, vY * s.y, vZ * s.z));

	XMLNode limitXMLNode = constraintXMLNode.getChildNode("Limit");

	if (_stricmp(constraintType, "Hinge") == 0) {
		btHingeConstraint* parentConstraint = new btHingeConstraint(*(parent->rigidBody()), *m_rigidBody, transformA, transformB);
		float low = static_cast<float>(atof(limitXMLNode.getAttribute("low", "0.0")));
		float high = static_cast<float>(atof(limitXMLNode.getAttribute("high", "0.75")));
		float softness = static_cast<float>(atof(limitXMLNode.getAttribute("softness", "0.9")));
		float biasFactor = static_cast<float>(atof(limitXMLNode.getAttribute("biasFactor", "0.3")));
		float relaxationFactor = static_cast<float>(atof(limitXMLNode.getAttribute("relaxationFactor", "1.0")));

		parentConstraint->setLimit(low, high, softness, biasFactor, relaxationFactor);
		m_parentConstraint = parentConstraint;
	} else if (_stricmp(constraintType, "ConeTwist") == 0) {
		btConeTwistConstraint* parentConstraint = new btConeTwistConstraint(*(parent->rigidBody()), *m_rigidBody, transformA, transformB);
		float swingSpan1 = static_cast<float>(atof(limitXMLNode.getAttribute("swingSpan1", "1.0")));
		float swingSpan2 = static_cast<float>(atof(limitXMLNode.getAttribute("swingSpan2", "1.0")));
		float twistSpan = static_cast<float>(atof(limitXMLNode.getAttribute("twistSpan", "1.0")));
		float softness = static_cast<float>(atof(limitXMLNode.getAttribute("softness", "0.9")));
		float biasFactor = static_cast<float>(atof(limitXMLNode.getAttribute("biasFactor", "0.3")));
		float relaxationFactor = static_cast<float>(atof(limitXMLNode.getAttribute("relaxationFactor", "1.0")));

		parentConstraint->setLimit(swingSpan1, swingSpan2, twistSpan, softness, biasFactor, relaxationFactor);
		m_parentConstraint = parentConstraint;
	}

	if(!ragdoll) Physics::instance()->addConstraint(m_parentConstraint);

}