hsBool plCullPoly::Validate() const { const float kMinMag = 1.e-8f; float magSq = fNorm.MagnitudeSquared(); if( magSq < kMinMag ) return false; if( fVerts.GetCount() < 3 ) return false; hsVector3 norm = hsVector3(&fVerts[1], &fVerts[0]) % hsVector3(&fVerts[2], &fVerts[0]); magSq = norm.MagnitudeSquared(); if( magSq < kMinMag ) return false; norm *= hsFastMath::InvSqrtAppr(magSq); int i; for( i = 3; i < fVerts.GetCount(); i++ ) { hsVector3 nextNorm = hsVector3(&fVerts[i-1], &fVerts[0]) % hsVector3(&fVerts[i], &fVerts[0]); magSq = nextNorm.MagnitudeSquared(); if( magSq < kMinMag ) return false; nextNorm *= hsFastMath::InvSqrtAppr(magSq); if( nextNorm.InnerProduct(norm) < kMinMag ) return false; } return true; }
void hsBounds3Ext::unalign() { fCorner = fMins; fExtFlags = 0; float x = fMaxs.X - fMins.X; if (x < 0.00001) { fExtFlags |= kAxisZeroZero; x = 1.0; } fAxes[0] = hsVector3(x, 0.0, 0.0); float y = fMaxs.Y - fMins.Y; if (y < 0.00001) { fExtFlags |= kAxisOneZero; y = 1.0; } fAxes[1] = hsVector3(0.0, y, 0.0); float z = fMaxs.Z - fMins.Z; if (z < 0.00001) { fExtFlags |= kAxisTwoZero; z = 1.0; } fAxes[2] = hsVector3(0.0, 0.0, z); }
static int pyVector3___init__(pyVector3* self, PyObject* args, PyObject* kwds) { float x = 0.0f, y = 0.0f, z = 0.0f; PyObject* init = NULL; static char* kwlist[] = { _pycs("X"), _pycs("Y"), _pycs("Z"), NULL }; static char* kwlist2[] = { _pycs("vector"), NULL }; if (PyArg_ParseTupleAndKeywords(args, kwds, "fff", kwlist, &x, &y, &z)) { (*self->fThis) = hsVector3(x, y, z); } else if (PyErr_Clear(), PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist2, &init)) { if (init == NULL) { (*self->fThis) = hsVector3(); return 0; } if (pyVector3_Check(init)) { (*self->fThis) = (*((pyVector3*)init)->fThis); } else { PyErr_SetString(PyExc_TypeError, "__init__ expects a vector"); return -1; } } else { return -1; } return 0; }
static bool PointsOnSameSide( const hsPoint3 &line1, const hsPoint3 &line2, const hsPoint3 &pointA, const hsPoint3 &pointB ) { hsVector3 baseVec( &line2, &line1 ); hsVector3 cp1 = hsVector3( &pointA, &line1 ) % baseVec; hsVector3 cp2 = hsVector3( &pointB, &line1 ) % baseVec; return ( cp1.fZ * cp2.fZ > 0 ) ? true : false; }
static int pySpanTemplateVertex_setUVWs(pySpanTemplateVertex* self, PyObject* value, void*) { hsTArray<hsVector3> uvws; if (value == NULL || !PyList_Check(value)) { PyErr_SetString(PyExc_TypeError, "UVWs should be a list of up to 10 hsVector3 objects"); return -1; } uvws.setSize(PyList_Size(value)); if (uvws.getSize() > 10) { PyErr_SetString(PyExc_RuntimeError, "UVWs should be a list of up to 10 hsVector3 objects"); return -1; } for (size_t i=0; i<uvws.getSize(); i++) { PyObject* itm = PyList_GetItem(value, i); if (!pyVector3_Check(itm)) { PyErr_SetString(PyExc_TypeError, "UVWs should be a list of up to 10 hsVector3 objects"); return -1; } uvws[i] = *((pyVector3*)itm)->fThis; } for (size_t i=0; i<uvws.getSize(); i++) self->fThis->fUVWs[i] = uvws[i]; for (size_t i=uvws.getSize(); i<10; i++) self->fThis->fUVWs[i] = hsVector3(0.0f, 0.0f, 0.0f); return 0; }
// // find the up vector for this object (if there are more than one, just the first one) PyObject* pySceneObject::GetRightVector() { // make sure that there are sceneobjects if ( fSceneObjects.Count() > 0 ) { // get the object pointer of just the first one in the list // (We really can't tell which one the user is thinking of if they are // referring to multiple objects, so the first one in the list will do.) plSceneObject* obj = plSceneObject::ConvertNoRef(fSceneObjects[0]->ObjectIsLoaded()); if ( obj ) { const plCoordinateInterface* ci = obj->GetCoordinateInterface(); if ( ci ) return pyVector3::New(ci->GetLocalToWorld().GetAxis(hsMatrix44::kRight)); else { plString errmsg = plString::Format("Sceneobject %s does not have a coordinate interface.", obj->GetKeyName().c_str()); PyErr_SetString(PyExc_RuntimeError, errmsg.c_str()); return nil; // return nil to tell python we errored } } } // if we couldn't find any sceneobject or a coordinate interface return pyVector3::New(hsVector3(0,0,0)); }
void plAnimatedMovementStrategy::IRecalcAngularVelocity(float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat) { fAnimAngularVel = 0.0f; float appliedVelocity = 0.0f; hsVector3 prevForward = GetYAxis(prevMat); hsVector3 curForward = GetYAxis(curMat); float angleSincePrev = AngleRad2d(curForward.fX, curForward.fY, prevForward.fX, prevForward.fY); bool sincePrevSign = angleSincePrev > 0.0f; if (angleSincePrev > float(M_PI)) angleSincePrev = angleSincePrev - TWO_PI; const hsVector3 startForward = hsVector3(0.0f, -1.0f, 0.0f); // the Y orientation of a "resting" armature.... float angleSinceStart = AngleRad2d(curForward.fX, curForward.fY, startForward.fX, startForward.fY); bool sinceStartSign = angleSinceStart > 0.0f; if (angleSinceStart > float(M_PI)) angleSinceStart = angleSinceStart - TWO_PI; // HANDLING ANIMATION WRAPPING: // under normal conditions, the angle from rest to the current frame will have the same // sign as the angle from the previous frame to the current frame. // if it does not, we have (most likely) wrapped the motivating animation from frame n back // to frame zero, creating a large angle from the previous frame to the current one if (sincePrevSign == sinceStartSign) { // signs are the same; didn't wrap; use the frame-to-frame angle difference appliedVelocity = angleSincePrev / elapsed; // rotation / time if (fabs(appliedVelocity) < 3) { fAnimAngularVel = appliedVelocity; } } }
static int pyPlane3___init__(pyPlane3* self, PyObject* args, PyObject* kwds) { float x = 0.0f, y = 0.0f, z = 0.0f, w = 0.0f; PyObject* init = NULL; static char* kwlist[] = { "X", "Y", "Z", "W", NULL }; static char* kwlist2[] = { "Plane", NULL }; if (PyArg_ParseTupleAndKeywords(args, kwds, "ffff", kwlist, &x, &y, &z, &w)) { (*self->fThis) = hsPlane3(hsVector3(x, y, z), w); } else if (PyErr_Clear(), PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist2, &init)) { if (init == NULL) { (*self->fThis) = hsPlane3(); return 0; } if (pyPlane3_Check(init)) { (*self->fThis) = (*((pyPlane3*)init)->fThis); } else { PyErr_SetString(PyExc_TypeError, "__init__ expects a Plane"); return -1; } } else { return -1; } return 0; }
PyObject* pySceneObject::GetAvatarVelocity() { // loop through all the sceneobject... looking for avatar modifiers int j; for ( j=0 ; j<fSceneObjects.Count() ; j++ ) { // get the object pointer of just the first one in the list // (We really can't tell which one the user is thinking of if they are // referring to multiple objects, so the first one in the list will do.) plSceneObject* obj = plSceneObject::ConvertNoRef(fSceneObjects[j]->ObjectIsLoaded()); if ( obj ) { // search through its modifiers to see if one of them is an avatar modifier int i; for ( i=0; i<obj->GetNumModifiers(); i++ ) { const plModifier* mod = obj->GetModifier(i); // see if it is an avatar mod base class const plArmatureMod* avatar = plArmatureMod::ConvertNoRef(mod); if ( avatar && avatar->GetController() ) { hsVector3 vel = avatar->GetController()->GetLinearVelocity(); return pyVector3::New(vel); } } } } // if we couldn't find any sceneobject that had an avatar mod then this ain't an avatar return pyVector3::New(hsVector3(0,0,0)); }
hsVector3 plAvBrainCritter::VectorToPlayer(unsigned long id) const { plArmatureMod* avatar = plAvatarMgr::GetInstance()->FindAvatarByPlayerID(id); if (!avatar) return hsVector3(0, 0, 0); hsPoint3 avPos; hsQuat avRot; avatar->GetPositionAndRotationSim(&avPos, &avRot); hsPoint3 creaturePos; hsQuat creatureRot; fAvMod->GetPositionAndRotationSim(&creaturePos, &creatureRot); return hsVector3(creaturePos - avPos); }
void plPXPhysicalControllerCore::IDrawDebugDisplay() { plDebugText &debugTxt = plDebugText::Instance(); char strBuf[ 2048 ]; int lineHeight = debugTxt.GetFontSize() + 4; uint32_t scrnWidth, scrnHeight; debugTxt.GetScreenSize( &scrnWidth, &scrnHeight ); int y = 10; int x = 10; sprintf(strBuf, "Controller Count: %d", gControllers.size()); debugTxt.DrawString(x, y, strBuf); y += lineHeight; debugTxt.DrawString(x, y, "Avatar Collisions:"); y += lineHeight; int i; for (i = 0; i < fDbgCollisionInfo.GetCount(); i++) { hsVector3 normal = fDbgCollisionInfo[i].fNormal; char *overlapStr = fDbgCollisionInfo[i].fOverlap ? "yes" : "no"; float angle = hsRadiansToDegrees(acos(normal * hsVector3(0, 0, 1))); sprintf(strBuf, " Obj: %s, Normal: (%.2f, %.2f, %.2f), Angle(%.1f), Overlap(%3s)", fDbgCollisionInfo[i].fSO->GetKeyName().c_str(), normal.fX, normal.fY, normal.fZ, angle, overlapStr); debugTxt.DrawString(x, y, strBuf); y += lineHeight; } }
void plCullNode::ITakeHalfPoly(const plCullPoly& srcPoly, const hsTArray<int>& vtxIdx, const hsBitVector& onVerts, plCullPoly& outPoly) const { if( vtxIdx.GetCount() > 2 ) { int i; for( i = 0; i < vtxIdx.GetCount(); i++ ) { int next = i < vtxIdx.GetCount()-1 ? i+1 : 0; int last = i ? i-1 : vtxIdx.GetCount()-1; // If these 3 verts are all on the plane, we may have created a collinear vertex (the middle one) // which we now want to skip. if( onVerts.IsBitSet(vtxIdx[i]) && onVerts.IsBitSet(vtxIdx[last]) && onVerts.IsBitSet(vtxIdx[next]) ) { #if 0 // FISH float dot = hsVector3(&srcPoly.fVerts[vtxIdx[last]], &srcPoly.fVerts[vtxIdx[i]]).InnerProduct(hsVector3(&srcPoly.fVerts[vtxIdx[next]], &srcPoly.fVerts[vtxIdx[i]])); if( dot <= 0 ) #endif // FISH continue; } if( srcPoly.fClipped.IsBitSet(vtxIdx[i]) ||(onVerts.IsBitSet(vtxIdx[i]) && onVerts.IsBitSet(vtxIdx[next])) ) outPoly.fClipped.SetBit(outPoly.fVerts.GetCount()); outPoly.fVerts.Append(srcPoly.fVerts[vtxIdx[i]]); } } else { // Just need a break point hsStatusMessage("Under 2"); // FISH } }
void plCullTree::IVisPolyEdge(const hsPoint3& p0, const hsPoint3& p1, hsBool dark) const { hsColorRGBA color; if( dark ) color.Set(0.2f, 0.2f, 0.2f, 1.f); else color.Set(1.f, 1.f, 1.f, 1.f); int vertStart = fVisVerts.GetCount(); hsVector3 dir0(&p0, &fViewPos); hsFastMath::NormalizeAppr(dir0); dir0 *= fVisYon; hsVector3 dir1(&p1, &fViewPos); hsFastMath::NormalizeAppr(dir1); dir1 *= fVisYon; hsPoint3 p3 = fViewPos; p3 += dir0; hsPoint3 p2 = fViewPos; p2 += dir1; hsVector3 norm = hsVector3(&p0, &fViewPos) % hsVector3(&p1, &fViewPos); hsFastMath::NormalizeAppr(norm); fVisVerts.Append(p0); fVisNorms.Append(norm); fVisColors.Append(color); fVisVerts.Append(p1); fVisNorms.Append(norm); fVisColors.Append(color); fVisVerts.Append(p2); fVisNorms.Append(norm); fVisColors.Append(color); fVisVerts.Append(p3); fVisNorms.Append(norm); fVisColors.Append(color); fVisTris.Append(vertStart + 0); fVisTris.Append(vertStart + 2); fVisTris.Append(vertStart + 1); fVisTris.Append(vertStart + 0); fVisTris.Append(vertStart + 3); fVisTris.Append(vertStart + 2); }
hsTArray<hsVector3> plSpanInstance::getPosDeltas() const { hsTArray<hsVector3> verts; verts.setSize(fNumVerts); switch (fEncoding.getCode() & plSpanEncoding::kPosMask) { case plSpanEncoding::kPos888: { unsigned char* pp = fPosDelta; for (unsigned int i=0; i<fNumVerts; i++) { verts[i].X = pp[0] * fEncoding.getPosScale(); verts[i].Y = pp[1] * fEncoding.getPosScale(); verts[i].Z = pp[2] * fEncoding.getPosScale(); pp += 3; } } break; case plSpanEncoding::kPos161616: { unsigned short* pp = (unsigned short*)fPosDelta; for (unsigned int i=0; i<fNumVerts; i++) { verts[i].X = pp[0] * fEncoding.getPosScale(); verts[i].Y = pp[1] * fEncoding.getPosScale(); verts[i].Z = pp[2] * fEncoding.getPosScale(); pp += 3; } } break; case plSpanEncoding::kPos101010: { unsigned int* pp = (unsigned int*)fPosDelta; for (unsigned int i=0; i<fNumVerts; i++) { verts[i].Z = ((*pp >> 20) & 0x3F) * fEncoding.getPosScale(); verts[i].Y = ((*pp >> 10) & 0x3F) * fEncoding.getPosScale(); verts[i].X = ((*pp >> 0) & 0x3F) * fEncoding.getPosScale(); pp++; } } break; case plSpanEncoding::kPos008: { unsigned char* pp = fPosDelta; for (unsigned int i=0; i<fNumVerts; i++) { verts[i].X = 0.0f; verts[i].Y = 0.0f; verts[i].Z = (*pp) * fEncoding.getPosScale(); pp++; } } break; default: for (unsigned int i=0; i<fNumVerts; i++) verts[i] = hsVector3(0.0f, 0.0f, 0.0f); break; } return verts; }
void plAvBrainCritter::SightCone(float coneRad) { fSightConeAngle = coneRad; // calculate the minimum dot product for the cone of sight (angle/2 vector dotted with straight ahead) hsVector3 straightVector(1, 0, 0), viewVector(1, 0, 0), up(0, 1, 0); hsQuat rotation(fSightConeAngle/2, &up); viewVector = hsVector3(rotation.Rotate(&viewVector)); viewVector.Normalize(); fSightConeDotMin = straightVector * viewVector; }
float plCullPoly::ICalcRadius() const { float radSq = 0; int i; for( i = 0; i < fVerts.GetCount(); i++ ) { float tmpSq = hsVector3(&fVerts[i], &fCenter).MagnitudeSquared(); if( tmpSq > radSq ) radSq = tmpSq; } return radSq * hsFastMath::InvSqrt(radSq); }
void plPhysicalControllerCore::MoveActorToSim() { // Get the current position of the physical hsPoint3 curLocalPos; hsPoint3 lastLocalPos; GetPositionSim(curLocalPos); MoveKinematicToController(curLocalPos); lastLocalPos=GetLocalPosition(); fDisplacementThisStep= hsVector3(curLocalPos - lastLocalPos); fLocalPosition = curLocalPos; if(fSimLength>0.0f) fAchievedLinearVelocity=fDisplacementThisStep/fSimLength; else fAchievedLinearVelocity.Set(0.0f,0.0f,0.0f); }
float plAnimPath::ICheckInterval(hsPoint3 &pt) const { if( fDelTime <= kTerminateDelTime && hsVector3(&fCurPos, &fPrevPos).MagnitudeSquared() < kTerminateDelDistSq) { return IBestTime(); } if( fThisTime < 0 ) return 0; if( fThisTime > fLength ) return fLength; if( GetFarthest() ) { if( (fLastDistSq > fThisDistSq)&&(fLastDistSq >= fNextDistSq) ) return IShiftBack(pt); if( (fNextDistSq > fThisDistSq)&&(fNextDistSq >= fLastDistSq) ) return IShiftFore(pt); if( (fThisDistSq >= fLastDistSq)&&(fLastDistSq >= fNextDistSq) ) return ISubDivBack(pt); if( (fThisDistSq >= fNextDistSq)&&(fNextDistSq >= fLastDistSq) ) return ISubDivFore(pt); } else { if( (fLastDistSq < fThisDistSq)&&(fLastDistSq <= fNextDistSq) ) return IShiftBack(pt); if( (fNextDistSq < fThisDistSq)&&(fNextDistSq <= fLastDistSq) ) return IShiftFore(pt); if( (fThisDistSq <= fLastDistSq)&&(fLastDistSq <= fNextDistSq) ) return ISubDivBack(pt); if( (fThisDistSq <= fNextDistSq)&&(fNextDistSq <= fLastDistSq) ) return ISubDivFore(pt); } hsAssert(false, "Shouldn't have gotten here"); return 0; }
void plPhysicalControllerCore::IncrementAngle(float deltaAngle) { float angle; hsVector3 axis; fLocalRotation.NormalizeIfNeeded(); fLocalRotation.GetAngleAxis(&angle, &axis); // adjust it (quaternions are weird...) if (axis.fZ < 0) angle = (2*M_PI) - angle; // axis is backwards, so reverse the angle too angle += deltaAngle; // make sure we wrap around if (angle < 0) angle = (2*M_PI) + angle; // angle is -, so this works like a subtract if (angle >= (2*M_PI)) angle = angle - (2*M_PI); // and set the new angle fLocalRotation.SetAngleAxis(angle, hsVector3(0,0,1)); }
// // Precompute array of arclen deltas for lookahead ability. // Changes current time! // void plAnimPath::ComputeArcLenDeltas(int32_t numSamples) { if (fArcLenDeltas.GetCount() >= numSamples) return; // already computed enough samples // compute arc len deltas fArcLenDeltas.Reset(); fArcLenDeltas.SetCount(numSamples); float animLen = GetLength(); float timeInc = animLen/(numSamples-1); // use num-1 since we'll create the zeroth entry by hand float time=0; hsPoint3 p1, p2; int32_t cnt=0; // prime initial point SetCurTime(0, kCalcPosOnly); GetPosition(&p1); ArcLenDeltaInfo aldi(time, 0); fArcLenDeltas[cnt++]=aldi; time += timeInc; bool quit=false; while(!quit && time<animLen+timeInc) { if (time > animLen || cnt+1 == numSamples) { time = animLen; quit=true; } SetCurTime(time, kCalcPosOnly); GetPosition(&p2); ArcLenDeltaInfo aldi(time, hsVector3(&p2, &p1).Magnitude()); fArcLenDeltas[cnt++]=aldi; time += timeInc; p1 = p2; } hsAssert(fArcLenDeltas.GetCount()==numSamples, "arcLenArray size wrong?"); hsAssert(cnt==numSamples, "arcLenArray size wrong?"); }
void hsMatrix44::MakeEnvMapMatrices(const hsPoint3& pos, hsMatrix44* worldToCameras, hsMatrix44* cameraToWorlds) { MakeCameraMatrices(pos, hsPoint3(pos.fX - 1.f, pos.fY, pos.fZ), hsVector3(0, 0, 1.f), worldToCameras[0], cameraToWorlds[0]); MakeCameraMatrices(pos, hsPoint3(pos.fX + 1.f, pos.fY, pos.fZ), hsVector3(0, 0, 1.f), worldToCameras[1], cameraToWorlds[1]); MakeCameraMatrices(pos, hsPoint3(pos.fX, pos.fY + 1.f, pos.fZ), hsVector3(0, 0, 1.f), worldToCameras[2], cameraToWorlds[2]); MakeCameraMatrices(pos, hsPoint3(pos.fX, pos.fY - 1.f, pos.fZ), hsVector3(0, 0, 1.f), worldToCameras[3], cameraToWorlds[3]); MakeCameraMatrices(pos, hsPoint3(pos.fX, pos.fY, pos.fZ + 1.f), hsVector3(0, -1.f, 0), worldToCameras[4], cameraToWorlds[4]); MakeCameraMatrices(pos, hsPoint3(pos.fX, pos.fY, pos.fZ - 1.f), hsVector3(0, 1.f, 0), worldToCameras[5], cameraToWorlds[5]); }
// There's actually a possibly faster way to do all this. // The barycentric coordinate in 3-space is the same as the barycentric coordinate of the projection // in 2-space, as long as the projection doesn't degenerate the triangle (i.e. project the tri onto // a plane perpindicular to the tri). The tri can't be perpindicular to all three major axes, so by // picking the right one (or just not picking the wrong one), the lengths of the cross products becomes // just the z component (e.g. v0.x*v1.y - v0.y*v1.x), so all the square roots go away (not to mention all // the vector math going from 3 component to 2). plTriUtils::Bary plTriUtils::ComputeBarycentricProjection(const hsPoint3& p0, const hsPoint3& p1, const hsPoint3& p2, hsPoint3&p, hsPoint3& out) { hsVector3 v12(&p1, &p2); hsVector3 v02(&p0, &p2); hsVector3 norm = Cross(v12, v02); float invLenSq12 = norm.MagnitudeSquared(); if( invLenSq12 < kAlmostZero ) return kDegenerateTri; // degenerate triangle invLenSq12 = 1.f / invLenSq12; p += norm * (hsVector3(&p2, &p).InnerProduct(norm) * invLenSq12); hsVector3 vp2(&p, &p2); hsVector3 v0 = Cross(v12, vp2); hsVector3 v1 = Cross(vp2, v02); return IComputeBarycentric(norm, invLenSq12, v0, v1, out); }
bool plDynaBulletMgr::IHandleShot(plBulletMsg* bull) { hsVector3 up = IRandomUp(bull->Dir()); hsPoint3 pos = bull->From() + bull->Dir() * (bull->Range() * 0.5f); fCutter->SetLength(hsVector3(bull->Radius() * fScale.fX, bull->Radius() * fScale.fY, bull->Range())); fCutter->Set(pos, up, -bull->Dir()); plDynaDecalInfo& info = IGetDecalInfo(uintptr_t(this), GetKey()); if( bull->PartyTime() > 0 ) fPartyTime = bull->PartyTime(); double secs = hsTimer::GetSysSeconds(); if( ICutoutTargets(secs) ) info.fLastTime = secs; return true; }
void plSwimStraightCurrentRegion::GetCurrent(plPhysicalControllerCore *physical, hsVector3 &linearResult, float &angularResult, float elapsed) { angularResult = 0.f; if (elapsed <= 0.f || GetProperty(kDisable)) { linearResult.Set(0.f, 0.f, 0.f); return; } hsPoint3 center, pos; hsVector3 current = fCurrentSO->GetLocalToWorld() * hsVector3(0.f, 1.f, 0.f); hsScalarTriple xlate = fCurrentSO->GetLocalToWorld().GetTranslate(); center.Set(&xlate); physical->GetPositionSim(pos); plKey worldKey = physical->GetSubworld(); if (worldKey) { plSceneObject* so = plSceneObject::ConvertNoRef(worldKey->ObjectIsLoaded()); hsMatrix44 w2l = so->GetWorldToLocal(); center = w2l * center; current = w2l * current; } hsVector3 pos2Center(center.fX - pos.fX, center.fY - pos.fY, 0.f); float dist = current.InnerProduct(pos - center); float pullVel; if (dist <= fNearDist) pullVel = fNearVel; else if (dist >= fFarDist) pullVel = fFarVel; else pullVel = fNearVel + (fFarVel - fNearVel) * (dist - fNearDist) / (fFarDist - fNearDist); linearResult = current * pullVel; }
static inline hsVector3 Cross(const hsScalarTriple& p0, const hsScalarTriple& p1) { return hsVector3(p0.fY * p1.fZ - p0.fZ * p1.fY, p0.fZ * p1.fX - p0.fX * p1.fZ, p0.fX * p1.fY - p0.fY * p1.fX); }
void plPXPhysical::ClearLinearVelocity() { SetLinearVelocitySim(hsVector3(0, 0, 0)); }
void plRidingAnimatedPhysicalStrategy::Apply(float delSecs) { hsVector3 LinearVelocity=fCore->GetLinearVelocity(); hsVector3 AchievedLinearVelocity=fCore->GetAchievedLinearVelocity(); if (fCore->IsKinematic()) { //want to make sure nothing funky happens in the sim IApplyKinematic(); return; } if (!fCore->IsEnabled()) return; //need to sweep ahead to see what we might hit. // if we hit anything we should probably apply the force that would normally be applied in fCore->SetPushingPhysical(nil); fCore->SetFacingPushingPhysical( false); plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded()); hsPoint3 startPos, desiredDestination, endPos; fCore->GetPositionSim(startPos); uint32_t collideFlags = 1<<plSimDefs::kGroupStatic | 1<<plSimDefs::kGroupAvatarBlocker | 1<<plSimDefs::kGroupDynamic; std::multiset<plControllerSweepRecord> GroundHitRecords; int possiblePlatformCount =fCore->SweepControllerPath(startPos, startPos + hsPoint3(0.f,0.f, -0.002f), true, true, collideFlags, GroundHitRecords); float maxPlatformVel = - FLT_MAX; int platformCount=0; fGroundHit = false; if(possiblePlatformCount) { std::multiset<plControllerSweepRecord>::iterator curRecord; for(curRecord = GroundHitRecords.begin(); curRecord != GroundHitRecords.end(); curRecord++) { hsBool groundlike=false; if((curRecord->locHit.fZ - startPos.fZ)<= .2) groundlike= true; if(groundlike) { if(curRecord->ObjHit !=nil) { hsVector3 vel; curRecord->ObjHit->GetLinearVelocitySim(vel); if(vel.fZ > maxPlatformVel) { maxPlatformVel= vel.fZ; } } platformCount ++; fGroundHit = true; } } } bool gotGroundHit = fGroundHit; if (so) { // If we've been moved since the last physics update (somebody warped us), // update the physics before we apply velocity. const hsMatrix44& l2w = so->GetCoordinateInterface()->GetLocalToWorld(); if (!CompareMatrices(l2w, fCore->GetLastGlobalLoc(), .0001f)) fCore->SetGlobalLoc(l2w); // Convert our avatar relative velocity to subworld relative if (!LinearVelocity.IsEmpty()) { LinearVelocity = l2w * LinearVelocity; const plCoordinateInterface* subworldCI = fCore->GetSubworldCI(); if (subworldCI) LinearVelocity = subworldCI->GetWorldToLocal() * LinearVelocity; } if(!IsOnGround()) { if(!fNeedVelocityOverride) { LinearVelocity.fZ= AchievedLinearVelocity.fZ; } else { LinearVelocity = fOverrideVelocity; } } if(fStartJump) { LinearVelocity.fZ =12.0f; } if(platformCount) { LinearVelocity.fZ = LinearVelocity.fZ + maxPlatformVel; } //probably neeed to do something with contact normals in here //for false ground stuff fFalseGround = false; hsVector3 testLength = LinearVelocity * delSecs + hsVector3(0.0, 0.0, -0.00f); // hsPoint3 desiredDestination= startPos + testLength; if(!IsOnGround()) { if(ICheckMove(startPos, desiredDestination)) {//we can get there soley by the LinearVelocity fNeedVelocityOverride =false; } else { fNeedVelocityOverride =true; fOverrideVelocity = LinearVelocity; fOverrideVelocity.fZ -= delSecs * 32.f; } } else { fNeedVelocityOverride =false; } fCore->SetLinearVelocity(LinearVelocity); } }
hsBool plDynaRippleVSMgr::IRippleFromShape(const plPrintShape* shape, hsBool force) { if( !ICheckRTMat() ) return false; if( !shape ) return false; hsBool retVal = false; plDynaDecalInfo& info = IGetDecalInfo(uintptr_t(shape), shape->GetKey()); const hsMatrix44& shapeL2W = shape->GetOwner()->GetLocalToWorld(); plConst(float) kMinDist(2.0f); plConst(float) kMinTime(1.5f); double t = hsTimer::GetSysSeconds(); float dt = float(t - info.fLastTime) * sRand.RandZeroToOne(); hsBool longEnough = (dt >= kMinTime); hsPoint3 xlate = shapeL2W.GetTranslate(); hsBool farEnough = (hsVector3(&info.fLastPos, &xlate).Magnitude() > kMinDist); if( force || longEnough || farEnough ) { hsPoint3 pos = shapeL2W.GetTranslate(); // We'll perturb the position a little so it doesn't look quite so regular, // but we perturb it more if we're just standing still hsVector3 randPert(sRand.RandMinusOneToOne(), sRand.RandMinusOneToOne(), 0); randPert.Normalize(); if( !farEnough ) { plConst(float) kRandPert = 0.5f; randPert *= kRandPert; } else { plConst(float) kRandPert = 0.15f; randPert *= kRandPert; } pos += randPert; // Are we potentially touching the water? float waterHeight = fWaveSetBase->GetHeight(); if( (pos.fZ - fScale.fZ * shape->GetHeight() < waterHeight) &&(pos.fZ + fScale.fZ * shape->GetHeight() > waterHeight) ) { hsVector3 dir(fWaveSetBase->GetWindDir()); hsVector3 up(0.f, 0.f, 1.f); float wid = hsMaximum(shape->GetWidth(), shape->GetLength()); plConst(float) kMaxWaterDepth(1000.f); hsVector3 size(wid * fScale.fX, wid * fScale.fY, kMaxWaterDepth); fCutter->SetLength(size); fCutter->Set(pos, dir, up); hsBool hit = ICutoutTargets(t); if( hit ) { info.fLastTime = t; info.fLastPos = shapeL2W.GetTranslate(); retVal = true; } else { retVal = false; // No-effect else just for break points. } } } return retVal; }
bool plRidingAnimatedPhysicalStrategy::ICheckMove(const hsPoint3& startPos, const hsPoint3& desiredPos) { //returns false if it believes the end result can't be obtained by pure application of velocity (collides into somthing that it can't climb up) //used as a way to check if it needs to hack getting there like in jumping uint32_t collideFlags = 1<<plSimDefs::kGroupStatic | 1<<plSimDefs::kGroupAvatarBlocker | 1<<plSimDefs::kGroupDynamic; bool hitBottomOfCapsule=false; bool hitOther=false; float timeOfOtherHits = FLT_MAX; float timeFirstBottomHit = -1.0; if(!fCore->IsSeeking()) { collideFlags|=(1<<plSimDefs::kGroupExcludeRegion); } if((desiredPos.fZ - startPos.fZ) < -1.f)//we will let gravity take care of it when falling return true; fContactNormals.SetCount(0); std::multiset< plControllerSweepRecord > DynamicHits; int NumberOfHits=fCore->SweepControllerPath(startPos, desiredPos, true, true, collideFlags, DynamicHits); hsPoint3 stepFromPoint; hsVector3 movementdir(&startPos, &desiredPos); movementdir.Normalize(); if(NumberOfHits) { hsPoint3 initBottomPos; fCore->GetPositionSim(initBottomPos); std::multiset< plControllerSweepRecord >::iterator cur; hsVector3 testLength(desiredPos - startPos); bool freeMove=true; for(cur = DynamicHits.begin(); cur != DynamicHits.end(); cur++) { if(movementdir.InnerProduct(cur->Norm)>0.01f) { hsVector3 topOfBottomHemAtTimeT=hsVector3(initBottomPos + testLength * cur->TimeHit ); topOfBottomHemAtTimeT.fZ = topOfBottomHemAtTimeT.fZ + fCore->GetControllerWidth(); if(cur->locHit.fZ <= (topOfBottomHemAtTimeT.fZ -.5f)) { hitBottomOfCapsule=true; hsVector3 norm= hsVector3(-1*(cur->locHit-topOfBottomHemAtTimeT)); norm.Normalize(); IAddContactNormals(norm); } else { return false; } } } return true; } else { return true; } }
void plBlower::IBlow(double secs, float delSecs) { hsPoint3 worldPos = fTarget->GetLocalToWorld().GetTranslate(); hsPoint3 localPos = fTarget->GetLocalToParent().GetTranslate(); // fast oscillation vs slow // Completely random walk in the rotation // Strength = Strength + rnd01 * (MaxStrength - Strength) float t = (fAccumTime += delSecs); float strength = 0; int i; for( i = 0; i < fOscillators.GetCount(); i++ ) { float c, s; t *= fOscillators[i].fFrequency * fMasterFrequency; t += fOscillators[i].fPhase; hsFastMath::SinCosAppr(t, s, c); c += fBias; strength += c * fOscillators[i].fPower; } strength *= fMasterPower; if( strength < 0 ) strength = 0; fDirection.fX += fRandom.RandMinusOneToOne() * delSecs * fDirectRate; fDirection.fY += fRandom.RandMinusOneToOne() * delSecs * fDirectRate; hsFastMath::NormalizeAppr(fDirection); float offDist = hsVector3(&fRestPos, &worldPos).Magnitude(); if( offDist > fMaxOffsetDist ) fMaxOffsetDist = offDist; hsVector3 force = fDirection * strength; static float kOffsetDistFrac = 0.5f; // make me const if( offDist > fMaxOffsetDist * kOffsetDistFrac ) { offDist /= fMaxOffsetDist; offDist *= fMasterPower; float impulse = offDist * delSecs * fImpulseRate; force.fX += impulse * fRandom.RandMinusOneToOne(); force.fY += impulse * fRandom.RandMinusOneToOne(); force.fZ += impulse * fRandom.RandMinusOneToOne(); } const float kOffsetDistDecay = 0.999f; fMaxOffsetDist *= kOffsetDistDecay; hsVector3 accel = force; accel += fSpringKonst * hsVector3(&fLocalRestPos, &localPos); hsVector3 del = accel * (delSecs * delSecs); fCurrDel = del; }