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);
}
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;
}
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;
}
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);
}
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;