BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_TRIGGER_ON_FACING_CHECK) IEnable(hWnd, Button_GetCheck((HWND)lParam) == BST_CHECKED); else if (msg == WM_INITDIALOG) IEnable(hWnd, (map->GetParamBlock()->GetInt(kVolumeTriggerOnFacing) != 0)); return FALSE; }
plPhysical& plPXPhysical::SetProperty(int prop, bool status) { if (GetProperty(prop) == status) { const char* propName = "(unknown)"; switch (prop) { case plSimulationInterface::kDisable: propName = "kDisable"; break; case plSimulationInterface::kPinned: propName = "kPinned"; break; case plSimulationInterface::kPassive: propName = "kPassive"; break; case plSimulationInterface::kPhysAnim: propName = "kPhysAnim"; break; case plSimulationInterface::kStartInactive: propName = "kStartInactive"; break; case plSimulationInterface::kNoSynchronize: propName = "kNoSynchronize"; break; } plString name = "(unknown)"; if (GetKey()) name = GetKeyName(); if (plSimulationMgr::fExtraProfile) plSimulationMgr::Log("Warning: Redundant physical property set (property %s, value %s) on %s", propName, status ? "true" : "false", name.c_str()); } switch (prop) { case plSimulationInterface::kDisable: IEnable(!status); break; case plSimulationInterface::kPinned: if (fActor->isDynamic()) { // if the body is already unpinned and you unpin it again, // you'll wipe out its velocity. hence the check. bool current = fActor->readBodyFlag(NX_BF_FROZEN); if (status != current) { if (status) fActor->raiseBodyFlag(NX_BF_FROZEN); else { fActor->clearBodyFlag(NX_BF_FROZEN); LogActivate("SetProperty"); fActor->wakeUp(); } } } break; } fProps.SetBit(prop, status); return *this; }
// Called after the simulation has run....sends new positions to the various scene objects // *** want to do this in response to an update message.... void plPXPhysical::SendNewLocation(bool synchTransform, bool isSynchUpdate) { // we only send if: // - the body is active or forceUpdate is on // - the mass is non-zero // - the physical is not passive bool bodyActive = !fActor->isSleeping(); bool dynamic = fActor->isDynamic(); if ((bodyActive || isSynchUpdate) && dynamic)// && fInitialTransform) { plProfile_Inc(MaySendLocation); if (!GetProperty(plSimulationInterface::kPassive)) { hsMatrix44 curl2w = fCachedLocal2World; // we're going to cache the transform before sending so we can recognize if it comes back IGetTransformGlobal(fCachedLocal2World); if (!CompareMatrices(curl2w, fCachedLocal2World, .0001f)) { plProfile_Inc(LocationsSent); plProfile_BeginLap(PhysicsUpdates, GetKeyName().c_str()); // quick peek at the translation...last time it was corrupted because we applied a non-unit quaternion // hsAssert(real_finite(fCachedLocal2World.fMap[0][3]) && // real_finite(fCachedLocal2World.fMap[1][3]) && // real_finite(fCachedLocal2World.fMap[2][3]), "Bad transform outgoing"); if (fCachedLocal2World.GetTranslate().fZ < kMaxNegativeZPos) { SimLog("Physical %s fell to %.1f (%.1f is the max). Suppressing.", GetKeyName().c_str(), fCachedLocal2World.GetTranslate().fZ, kMaxNegativeZPos); // Since this has probably been falling for a while, and thus not getting any syncs, // make sure to save it's current pos so we'll know to reset it later DirtySynchState(kSDLPhysical, plSynchedObject::kBCastToClients); IEnable(false); } hsMatrix44 w2l; fCachedLocal2World.GetInverse(&w2l); plCorrectionMsg *pCorrMsg = new plCorrectionMsg(GetObjectKey(), fCachedLocal2World, w2l, synchTransform); pCorrMsg->Send(); if (fProxyGen) fProxyGen->SetTransform(fCachedLocal2World, w2l); plProfile_EndLap(PhysicsUpdates, GetKeyName().c_str()); } } } }
bool plPXPhysical::Init(PhysRecipe& recipe) { bool startAsleep = false; fBoundsType = recipe.bounds; fGroup = recipe.group; fReportsOn = recipe.reportsOn; fObjectKey = recipe.objectKey; fSceneNode = recipe.sceneNode; fWorldKey = recipe.worldKey; NxActorDesc actorDesc; NxSphereShapeDesc sphereDesc; NxConvexShapeDesc convexShapeDesc; NxTriangleMeshShapeDesc trimeshShapeDesc; NxBoxShapeDesc boxDesc; plPXConvert::Matrix(recipe.l2s, actorDesc.globalPose); switch (fBoundsType) { case plSimDefs::kSphereBounds: { hsMatrix44 sphereL2W; sphereL2W.Reset(); sphereL2W.SetTranslate(&recipe.offset); sphereDesc.radius = recipe.radius; plPXConvert::Matrix(sphereL2W, sphereDesc.localPose); sphereDesc.group = fGroup; actorDesc.shapes.pushBack(&sphereDesc); } break; case plSimDefs::kHullBounds: // FIXME PHYSX - Remove when hull detection is fixed // If this is read time (ie, meshStream is nil), turn the convex hull // into a box. That way the data won't have to change when convex hulls // actually work right. if (fGroup == plSimDefs::kGroupDetector && recipe.meshStream == nil) { #ifdef USE_BOXES_FOR_DETECTOR_HULLS MakeBoxFromHull(recipe.convexMesh, boxDesc); plSimulationMgr::GetInstance()->GetSDK()->releaseConvexMesh(*recipe.convexMesh); boxDesc.group = fGroup; actorDesc.shapes.push_back(&boxDesc); #else #ifdef USE_PHYSX_CONVEXHULL_WORKAROUND // make a hull of planes for testing IsInside IMakeHull(recipe.convexMesh,recipe.l2s); #endif // USE_PHYSX_CONVEXHULL_WORKAROUND convexShapeDesc.meshData = recipe.convexMesh; convexShapeDesc.userData = recipe.meshStream; convexShapeDesc.group = fGroup; actorDesc.shapes.pushBack(&convexShapeDesc); #endif // USE_BOXES_FOR_DETECTOR_HULLS } else { convexShapeDesc.meshData = recipe.convexMesh; convexShapeDesc.userData = recipe.meshStream; convexShapeDesc.group = fGroup; actorDesc.shapes.pushBack(&convexShapeDesc); } break; case plSimDefs::kBoxBounds: { boxDesc.dimensions = plPXConvert::Point(recipe.bDimensions); hsMatrix44 boxL2W; boxL2W.Reset(); boxL2W.SetTranslate(&recipe.bOffset); plPXConvert::Matrix(boxL2W, boxDesc.localPose); boxDesc.group = fGroup; actorDesc.shapes.push_back(&boxDesc); } break; case plSimDefs::kExplicitBounds: case plSimDefs::kProxyBounds: if (fGroup == plSimDefs::kGroupDetector) { SimLog("Someone using an Exact on a detector region: %s", GetKeyName().c_str()); } trimeshShapeDesc.meshData = recipe.triMesh; trimeshShapeDesc.userData = recipe.meshStream; trimeshShapeDesc.group = fGroup; actorDesc.shapes.pushBack(&trimeshShapeDesc); break; default: hsAssert(false, "Unknown geometry type during read."); return false; break; } // Now fill out the body, or dynamic part of the physical NxBodyDesc bodyDesc; fMass = recipe.mass; if (recipe.mass != 0) { bodyDesc.mass = recipe.mass; actorDesc.body = &bodyDesc; if (GetProperty(plSimulationInterface::kPinned)) { bodyDesc.flags |= NX_BF_FROZEN; startAsleep = true; // put it to sleep if they are going to be frozen } if (fGroup != plSimDefs::kGroupDynamic || GetProperty(plSimulationInterface::kPhysAnim)) { SetProperty(plSimulationInterface::kPassive, true); // Even though the code for animated physicals and animated activators are the same // keep these code snippets separated for fine tuning. Thanks. if (fGroup == plSimDefs::kGroupDynamic) { // handle the animated physicals.... make kinematic for now. fNumberAnimatedPhysicals++; bodyDesc.flags |= NX_BF_KINEMATIC; startAsleep = true; } else { // handle the animated activators.... fNumberAnimatedActivators++; bodyDesc.flags |= NX_BF_KINEMATIC; startAsleep = true; } } } else { if ( GetProperty(plSimulationInterface::kPhysAnim) ) SimLog("An animated physical that has no mass: %s", GetKeyName().c_str()); } actorDesc.userData = this; actorDesc.name = GetKeyName().c_str(); // Put the dynamics into actor group 1. The actor groups are only used for // deciding who we get contact reports for. if (fGroup == plSimDefs::kGroupDynamic) actorDesc.group = 1; NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey); try { fActor = scene->createActor(actorDesc); } catch (...) { hsAssert(false, "Actor creation crashed"); return false; } hsAssert(fActor, "Actor creation failed"); if (!fActor) return false; NxShape* shape = fActor->getShapes()[0]; shape->setMaterial(plSimulationMgr::GetInstance()->GetMaterialIdx(scene, recipe.friction, recipe.restitution)); // Turn on the trigger flags for any detectors. // // Normally, we'd set these flags on the shape before it's created. However, // in the case where the detector is going to be animated, it'll have a rigid // body too, and that will cause problems at creation. According to Ageia, // a detector shape doesn't actually count as a shape, so the SDK will have // problems trying to calculate an intertial tensor. By letting it be // created as a normal dynamic first, then setting the flags, we work around // that problem. if (fGroup == plSimDefs::kGroupDetector) { shape->setFlag(NX_TRIGGER_ON_ENTER, true); shape->setFlag(NX_TRIGGER_ON_LEAVE, true); } if (GetProperty(plSimulationInterface::kStartInactive) || startAsleep) { if (!fActor->isSleeping()) { if (plSimulationMgr::fExtraProfile) SimLog("Deactivating %s in SetPositionAndRotationSim", GetKeyName().c_str()); fActor->putToSleep(); } } if (GetProperty(plSimulationInterface::kDisable)) IEnable(false); if (GetProperty(plSimulationInterface::kSuppressed_DEAD)) IEnable(false); plNodeRefMsg* refMsg = new plNodeRefMsg(fSceneNode, plRefMsg::kOnCreate, -1, plNodeRefMsg::kPhysical); hsgResMgr::ResMgr()->AddViaNotify(GetKey(), refMsg, plRefFlags::kActiveRef); if (fWorldKey) { plGenRefMsg* ref = new plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kPhysRefWorld); hsgResMgr::ResMgr()->AddViaNotify(fWorldKey, ref, plRefFlags::kActiveRef); } // only dynamic physicals without noSync need SDLs if ( fGroup == plSimDefs::kGroupDynamic && !fProps.IsBitSet(plSimulationInterface::kNoSynchronize) ) { // add SDL modifier plSceneObject* sceneObj = plSceneObject::ConvertNoRef(fObjectKey->ObjectIsLoaded()); hsAssert(sceneObj, "nil sceneObject, failed to create and attach SDL modifier"); delete fSDLMod; fSDLMod = new plPhysicalSDLModifier; sceneObj->AddModifier(fSDLMod); } return true; }
// send disable message to the plKey void pyKey::Disable() { IEnable(false); }
// send enable message to the plKey void pyKey::Enable() { IEnable(true); }