Newton Drag and Drop for Irrlicht

A forum to store posts deemed exceptionally wise and useful
Post Reply
pfo
Posts: 370
Joined: Mon Aug 29, 2005 10:54 pm
Location: http://web.utk.edu/~pfox1

Newton Drag and Drop for Irrlicht

Post by pfo »

Finally got this working, its pretty much the same as in the Newton SDK, but modified to work with Irrlicht vectors / matrices:

Drag and Drop Force and Torque Callback:

Code: Select all

void onApplyDragForceAndTorque(const NewtonBody *body)
{
	// Do nothing if mass is 0 (static body...)
	float	Mass, Ixx, Iyy, Izz;
	NewtonBodyGetMassMatrix(body, &Mass, &Ixx, &Iyy, &Izz);
	if (Mass == 0.0f)
		return;
/*     // my gravity function, default force and torque callback
	// call default force and torque callback (gravity..)
	DObject::onApplyGravity(body);
*/
	core::vector3df	force, velocity, omega, damp;

	NewtonBodyGetVelocity(body, &velocity.X);
	NewtonBodyGetOmega(body, &omega.X);

	// calculate force and dampen it a little
	force = g_vDragForce * (Mass * 50.0f);
	damp = velocity * (Mass * 5.0f);
	force -= damp;

	// calculate torque and dampen it a little
	core::matrix4	matrix;
	NewtonBodyGetMatrix(body, &matrix.M[0]);
	core::vector3df	point = g_vDragAttachmentPoint;
	matrix.rotateVect(point);
	core::vector3df	torque = point.crossProduct(force);
	damp = omega * Mass * 10.0f;
	torque -= damp;

	// add force and torque to body
	NewtonBodyAddForce(body, &force.X);
	NewtonBodyAddTorque(body, &torque.X);
}
Then in your event receiver, you need these:

Code: Select all

	// handle drag and drop events
	if (the_event->EventType == EET_MOUSE_INPUT_EVENT && m_bAllowDrag)
	{
		switch (the_event->MouseInput.Event)
		{
	// select object
	case EMIE_LMOUSE_PRESSED_DOWN:
		{
			// if there was a previous body, reset its force and torque callback
			if (g_pDragBody)	NewtonBodySetForceAndTorqueCallback(g_pDragBody, onApplyGravity);

			// pick object
			core::position2d<s32>	pos = g_device->getCursorControl()->getPosition();
			core::line3df			ray = g_col->getRayFromScreenCoordinates(pos);
			g_pDragBody = PickObject(pos, ray, false);

			// enable drag force if object picked
			if (g_pDragBody)
			{
				g_nDragDistance = GetPickedDistance();

				// get point that was picked
				core::matrix4	matrix;
				NewtonBodyGetMatrix(g_pDragBody, &matrix.M[0]);

				// get attachment point local to body
				core::vector3df	diff = (ray.end - ray.start) * g_nDragDistance;
				g_vDragAttachmentPoint = (ray.start + diff) - matrix.getTranslation();
				matrix.inverseRotateVect(g_vDragAttachmentPoint);

				// override force and torque callback
				NewtonBodySetForceAndTorqueCallback(g_pDragBody, onApplyDragForceAndTorque);
				m_bDragObject = true;

				// show the drag points and hide the cursor
				m_pDragStartBB->setVisible(true);
				m_pDragEndBB->setVisible(true);
				g_device->getCursorControl()->setVisible(false);				
			}
			else
			{								
				// hide the drag points and show cursor
				m_bDragObject = false;
				m_pDragStartBB->setVisible(false);
				m_pDragEndBB->setVisible(false);
				g_device->getCursorControl()->setVisible(true);
			}
		}
		break;
		// release object if we were dragging
		case EMIE_LMOUSE_LEFT_UP:
			if (m_bDragObject)
			{
				// reset force and torque callback and reset drag object flag
				NewtonBodySetForceAndTorqueCallback(g_pDragBody, onApplyGravity);
				m_bDragObject = false;
				g_pDragBody = NULL;

				// hide the drag points and show cursor
				m_pDragStartBB->setVisible(false);
				m_pDragEndBB->setVisible(false);
				g_device->getCursorControl()->setVisible(true);
			}
			break;
		// move object forward / backward if dragging
		case EMIE_MOUSE_WHEEL:
			if (m_bDragObject)
				g_nDragDistance += 0.00025f * the_event->MouseInput.Wheel;
			break;
		}
This is PickObject:

Code: Select all

// Picking helper variables
NewtonBody		*g_pPickedBody = NULL;
float			g_nPickedParam = 1.1f;

// Pick function
dFloat Pick(const NewtonBody* body, const dFloat* normal, int collisionID, void* userData, dFloat intersectParam)
{
	if (intersectParam <  g_nPickedParam) {
		g_nPickedParam = intersectParam;
		g_pPickedBody = (NewtonBody*)body;
	}

	return intersectParam;
}

NewtonBody *PickObject(core::position2d<s32> pos, core::line3df ray, bool bAllowStatic)
{
	// check if we're over any element and abort
	gui::IGUIElement		*pElement = g_gui->getRootGUIElement()->getElementFromPoint(pos);
	if (pElement != g_gui->getRootGUIElement())
		return NULL;

	// pick object
	g_pPickedBody = NULL;
	g_nPickedParam = 1.1f;
	NewtonWorldRayCast(g_pNewtonWorld, &ray.start.X, &ray.end.X, Pick, NULL);

	// check if we allow static bodies
	if (g_pPickedBody && !bAllowStatic)	{
		float	Mass, Ixx, Iyy, Izz;
		NewtonBodyGetMassMatrix(g_pPickedBody, &Mass, &Ixx, &Iyy, &Izz);
		if (Mass == 0.0f)
			return NULL;
	}

	// return picked body
	return g_pPickedBody;
}
My, this is getting very long, for those of you still with me there's one more thing to add, somewhere each frame you must do the following:

Code: Select all

	// calculate drag force if we're dragging an object
	if (m_bDragObject)
	{
		// get body matrix
		core::matrix4		matrix;
		NewtonBodyGetMatrix(g_pDragBody, &matrix.M[0]);


		// get ray from screen
		core::line3d<f32>	ray = g_col->getRayFromScreenCoordinates(g_device->getCursorControl()->getPosition());

		// get drag point on body
		core::vector3df	point = g_vDragAttachmentPoint;
		matrix.transformVect(point);

		// calculate the force at that point based on mouse position
		core::vector3df		diff = (ray.end - ray.start) * g_nDragDistance;
		core::vector3df		force = ray.start + diff;
		g_vDragForce = force - point;

		// set drag point positions
		m_pDragStartBB->setPosition(force);
		m_pDragEndBB->setPosition(point);

		// draw line b/w points
		core::position2d<s32>	p0 = g_col->getScreenCoordinatesFrom3DPosition(force);
		core::position2d<s32>	p1 = g_col->getScreenCoordinatesFrom3DPosition(point);
		g_driver->draw2DLine(p0, p1, g_cRed);
	}
Enjoy, let me know if you have problems integrating, as I think I've seen them all at this point (lol, this took forever to figure out).

EDIT: m_pDragStartBB and m_pDragEndBB are just billboard scene nodes that represent a red circle, nothing fancy. The results look similar to the drag points in the Newton SDK.

EDIT2: I omitted a function, GetPickedDistance(), all this returns is g_nPickedParam from PickObject.

EDIT3: You're supposed to do point.crossProduct(force); in the drag callback, not point * force;
Last edited by pfo on Sun Dec 04, 2005 9:00 pm, edited 2 times in total.
zenoid
Posts: 40
Joined: Wed Jul 20, 2005 1:16 pm
Location: france
Contact:

Post by zenoid »

many THX for sharing this. I'll check that as soon as possible.
noone88
Posts: 49
Joined: Sat May 27, 2006 3:28 pm

Post by noone88 »

thanks dude
Post Reply