bool CCameraTracking::Update(SViewParams &viewParams, float &fHOffObstacleStrength, const SCamModeSettings &camMode, const CPlayer &hero, bool bObstacleFound /* = false */) { if(!g_pGameCVars->cl_cam_tracking || !m_pCamRayScan) return false; m_fFrameTime = max(g_fCamError, gEnv->pTimer->GetFrameTime()); //in combat mode this function doesn't really avoid obstacles, it avoids clipping float fCombatModeWeight = 5.0f; //default angle and minimum const float fNow = gEnv->pTimer->GetFrameStartTime().GetSeconds(); CCameraInputHelper *pCamHelper = hero.GetCameraInputHelper(); CRY_ASSERT(pCamHelper); float fLastUserInput = pCamHelper->GetLastUserInputTime(); //user input overrides auto-follow if(fNow - fLastUserInput < 0.5f) return false; bool bTrackingActive = camMode.camType == ECT_CamFollow && (camMode.collisionType == ECCT_CollisionTrack || camMode.collisionType == ECCT_CollisionTrackOrCut); //get current values Vec3 curCamDir = viewParams.position-viewParams.targetPos; m_curCamOrientation.Set(0.0f, 0.0f, 0.0f); CartesianToSpherical(curCamDir, m_curCamOrientation); curCamDir.Normalize(); if(m_curCamOrientation.m_fDist < g_pGameCVars->cl_cam_min_distance) m_curCamOrientation.m_fDist = g_pGameCVars->cl_cam_min_distance; //work in 0 .. 2PI m_curCamOrientation.m_fYaw += gf_PI; //if there is something in the way if(bObstacleFound) { //re-start fadeout m_fTimeCovered = 0.5f; //set last obstacle pos m_vLastObstaclePos = viewParams.position; //scan obstacle if(!IdentifyObstacle(curCamDir, hero)) return false; } else if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError) { //if there is nothing in the way, fade out the movement //time based fade if(m_fTimeCovered > 0) { m_fTimeCovered = max(m_fTimeCovered - m_fFrameTime, 0.0f); //these interpolators should be time and not frame based m_fYawDelta = (g_fInterpolationRate * m_fYawDelta) * g_fInterpolationWeight; m_fPitchDelta = (g_fInterpolationRate * m_fPitchDelta) * g_fInterpolationWeight; m_fSpeed = (g_fInterpolationRate * m_fSpeed) * g_fInterpolationWeight; } else { m_fYawDelta = 0.0f; m_fPitchDelta = 0.0f; m_fSpeed = 0.0f; } } //apply delta rotation for obstacle avoidance if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError) { if(bTrackingActive) { //set new yaw float newYaw = m_curCamOrientation.m_fYaw + m_fYawDelta; //re-align yaw //the camera direction is 90 degrees off and flipped compared to entity space newYaw = (newYaw - gf_PI * 0.5f) * -1.0f; //set new pitch float newPitch = m_curCamOrientation.m_fPitch + m_fPitchDelta; if(g_pGameCVars->cl_cam_orbit != 0) { //pCamHelper->SetTrackingDelta(-m_fYawDelta, m_fPitchDelta); pCamHelper->SetYawDelta(-m_fYawDelta); pCamHelper->SetPitchDelta(m_fPitchDelta); } else { //apply yaw/pitch on camera //pCamHelper->SetInterpolationTarget(newYaw, newPitch, gf_PI, 0.1f, 0.0f); //this will always reset follow cam interpolation pCamHelper->SetYawDelta(m_fYawDelta); pCamHelper->SetPitchDelta(m_fPitchDelta); } } else { //in orbit mode we basically simulate user input //pCamHelper->SetTrackingDelta(-fCombatModeWeight*g_fYawDelta, fCombatModeWeight*g_fPitchDelta); //in cutting mode we offset the camera to avoid clipping float offsetStrength = 0.0f; float offsetSpeed = 2.0f; if(bObstacleFound) { offsetStrength = (m_fYawDelta < 0.0f)?-g_fOffsetTrackingDistance:g_fOffsetTrackingDistance; offsetSpeed = 0.5f; } fHOffObstacleStrength = InterpolateTo(fHOffObstacleStrength, offsetStrength, offsetSpeed); } //CryLogAlways("new yaw %f, yawDelta %f", newYaw, g_yawDelta); return true; } else UpdateAutoFollow(viewParams, hero); return false; }
bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2, const Vec3<double> & p3, const Vec3<double> & p4, Vec3<double> & pa, Vec3<double> & pb, double & mua, double & mub) { Vec3<double> p13,p43,p21; double d1343,d4321,d1321,d4343,d2121; double numer,denom; p13.X() = p1.X() - p3.X(); p13.Y() = p1.Y() - p3.Y(); p13.Z() = p1.Z() - p3.Z(); p43.X() = p4.X() - p3.X(); p43.Y() = p4.Y() - p3.Y(); p43.Z() = p4.Z() - p3.Z(); if (p43.X()==0.0 && p43.Y()==0.0 && p43.Z()==0.0) return false; p21.X() = p2.X() - p1.X(); p21.Y() = p2.Y() - p1.Y(); p21.Z() = p2.Z() - p1.Z(); if (p21.X()==0.0 && p21.Y()==0.0 && p21.Z()==0.0) return false; d1343 = p13.X() * p43.X() + p13.Y() * p43.Y() + p13.Z() * p43.Z(); d4321 = p43.X() * p21.X() + p43.Y() * p21.Y() + p43.Z() * p21.Z(); d1321 = p13.X() * p21.X() + p13.Y() * p21.Y() + p13.Z() * p21.Z(); d4343 = p43.X() * p43.X() + p43.Y() * p43.Y() + p43.Z() * p43.Z(); d2121 = p21.X() * p21.X() + p21.Y() * p21.Y() + p21.Z() * p21.Z(); denom = d2121 * d4343 - d4321 * d4321; if (denom==0.0) return false; numer = d1343 * d4321 - d1321 * d4343; mua = numer / denom; mub = (d1343 + d4321 * (mua)) / d4343; pa.X() = p1.X() + mua * p21.X(); pa.Y() = p1.Y() + mua * p21.Y(); pa.Z() = p1.Z() + mua * p21.Z(); pb.X() = p3.X() + mub * p43.X(); pb.Y() = p3.Y() + mub * p43.Y(); pb.Z() = p3.Z() + mub * p43.Z(); return true; }
Vec4 RayTracer::traceLights(const Vec3& intersection, Drawable *drawable, Vec3 eye ) { Vec4 out_color; Vec4 spec_color; Vec4 diffuse_color = drawable->getColorAt(intersection); float factor_ambient = drawable->getMaterial().getAmbientFactor(); LightVector::iterator light = _scene->getLights().begin(); while (light != _scene->getLights().end()) { //Vec3 light_direction = intersection - (*light)->getPosition(); Vec3 light_direction = (*light)->getPosition() - intersection; float lightdist = light_direction.length(); light_direction.normalize(); Ray ray(intersection, light_direction); float light_scaling = drawable->getNormalAt(intersection) * light_direction; // no effect if light ray and object normal are orthogonal if (light_scaling < 0) light_scaling = 0.0f; // check for shadows DrawableVector::iterator object = _scene->getDrawables().begin(); Drawable *hitobject = 0; while (object != _scene->getDrawables().end()) { float tmp; Vec3 tmp_intersection; // nothing to do if current object is the drawable if ( ((*object) != drawable) && (*object)->intersect(ray, tmp_intersection, tmp) ) { // object is between drawable and current light Vec3 intersection_vec = tmp_intersection - (*light)->getPosition(); float dist = intersection_vec.length(); if ( dist < lightdist) { hitobject = *object; break; } } object++; } // do specular component if ( !hitobject ) { switch ((*light)->getType()) { case Light::DIRECTIONAL: out_color += (*light)->getColor() * (*light)->getIntensity(); out_color += (*light)->getAmbientColor() * factor_ambient; break; case Light::POINT: { out_color += (*light)->getColor() * (*light)->getIntensity() * light_scaling * 1.0f/(lightdist); Vec3 half = light_direction - eye; half.normalize(); Vec3 normal = drawable->getNormalAt(intersection); normal.normalize(); float shine = 16.0f; float temp = MAX(0.0, normal * half); float spec_val = pow(temp, shine); spec_color += (*light)->getColor() * (*light)->getIntensity() * spec_val * drawable->getMaterial().getReflectionFactor(); out_color += (*light)->getAmbientColor() * factor_ambient; break; } default: break; } } light++; } out_color = diffuse_color.componentMultiply(out_color); out_color += spec_color; return out_color; }
/** findOutOfRoadSector finds the sector where XYZ is, but as it name implies, it is more accurate for the outside of the track than the inside, and for STK's needs the accuracy on top of the track is unacceptable; but if this was a 2D function, the accuracy for out of road sectors would be perfect. To find the sector we look for the closest line segment from the right and left drivelines, and the number of that segment will be the sector. The SIDE argument is used to speed up the function only; if we know that XYZ is on the left or right side of the track, we know that the closest driveline must be the one that matches that condition. In reality, the side used in STK is the one from the previous frame, but in order to move from one side to another a point would go through the middle, that is handled by findRoadSector() which doesn't has speed ups based on the side. NOTE: This method of finding the sector outside of the road is *not* perfect: if two line segments have a similar altitude (but enough to let a kart get through) and they are very close on a 2D system, if a kart is on the air it could be closer to the top line segment even if it is supposed to be on the sector of the lower line segment. Probably the best solution would be to construct a quad that reaches until the next higher overlapping line segment, and find the closest one to XYZ. */ int QuadGraph::findOutOfRoadSector(const Vec3& xyz, const int curr_sector, std::vector<int> *all_sectors) const { int count = (all_sectors!=NULL) ? (int) all_sectors->size() : getNumNodes(); int current_sector = 0; if(curr_sector != UNKNOWN_SECTOR && !all_sectors) { // We have to test all nodes here: reason is that on track with // shortcuts the n quads of the main drivelines is followed by // the quads of the shortcuts. So after quad n-1 (the last one // before the lap counting line) quad n will not be 0 (the first // quad after the lap counting line), but one of the quads on a // shortcut. If we only tested a limited number of quads to // improve the performance the crossing of a lap might not be // detected (because quad 0 is not tested, only quads on the // shortcuts are tested). If this should become a performance // bottleneck, we need to set up a graph of 'next' quads for each // quad (similar to what the AI does), and only test the quads // in this graph. const int LIMIT = getNumNodes(); count = LIMIT; // Start 10 quads before the current quad, so the quads closest // to the current position are tested first. current_sector = curr_sector -10; if(current_sector<0) current_sector += getNumNodes(); } int min_sector = UNKNOWN_SECTOR; float min_dist_2 = 999999.0f*999999.0f; // If a kart is falling and in between (or too far below) // a driveline point it might not fulfill // the height condition. So we run the test twice: first with height // condition, then again without the height condition - just to make sure // it always comes back with some kind of quad. for(int phase=0; phase<2; phase++) { for(int j=0; j<count; j++) { int next_sector; if(all_sectors) next_sector = (*all_sectors)[j]; else next_sector = current_sector+1 == (int)getNumNodes() ? 0 : current_sector+1; // A first simple test uses the 2d distance to the center of the quad. float dist_2 = m_all_nodes[next_sector]->getDistance2FromPoint(xyz); if(dist_2<min_dist_2) { const Quad &q = getQuadOfNode(next_sector); float dist = xyz.getY() - q.getMinHeight(); // While negative distances are unlikely, we allow some small // negative numbers in case that the kart is partly in the // track. Only do the height test in phase==0, in phase==1 // accept any point, independent of height. if(phase==1 || (dist < 5.0f && dist>-1.0f) ) { min_dist_2 = dist_2; min_sector = next_sector; } } current_sector = next_sector; } // for j // Leave in phase 0 if any sector was found. if(min_sector!=UNKNOWN_SECTOR) return min_sector; } // phase if(min_sector==UNKNOWN_SECTOR ) { Log::info("Quad Grap", "unknown sector found."); } return min_sector; } // findOutOfRoadSector
//------------------------------------------------------------------------ void CVehicleMovementWarrior::Update(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); if (!IsCollapsing()) CVehicleMovementHovercraft::Update(deltaTime); else CVehicleMovementBase::Update(deltaTime); if (IsCollapsing()) { m_collapseTimer += deltaTime; // check platform Vec3 platformPos; if (m_pPlatformPos) platformPos = m_pPlatformPos->GetWorldTM().GetTranslation(); else platformPos.zero(); float dist = platformPos.z - GetISystem()->GetI3DEngine()->GetTerrainElevation(platformPos.x, platformPos.y); if (dist < 1.f) { m_platformDown = true; } // center turret RotatePart(m_pTurret, DEG2RAD(0.f), AXIS_Z, DEG2RAD(2.5f), deltaTime); // take down wing and cannon RotatePart(m_pWing, DEG2RAD(-12.5f), AXIS_X, DEG2RAD(3.f), deltaTime); RotatePart(m_pCannon, DEG2RAD(-20.f), AXIS_X, DEG2RAD(2.5f), deltaTime); if (!m_platformDown) { // handle legs to bring down platform TThrusters::iterator iter; for (iter=m_vecThrusters.begin(); iter!=m_vecThrusters.end(); ++iter) { SThruster* pThruster = *iter; if (pThruster->heightAdaption <= 0.f) { pThruster->hoverHeight = max(0.1f, pThruster->hoverHeight - 0.6f*deltaTime); continue; } else { //if (!pThruster->groundContact) //pThruster->hoverHeight = max(0.1f, pThruster->hoverHeight - 0.2f*deltaTime); } /* // special legs control float collapseSpeed = DEG2RAD(5.f); float maxDistMovable = 1.f/0.8f; float dist = (isneg(pThruster->prevDist)) ? 0.f : pThruster->hoverHeight - pThruster->prevDist; if (isneg(dist)) { collapseSpeed *= max(0.f, 1.f + maxDistMovable*dist); } if (collapseSpeed > 0.f) { float angle = RotatePart(pThruster->pParentPart, DEG2RAD(m_collapsedLegAngle), collapseSpeed, deltaTime); RotatePart(pThruster->pPart, DEG2RAD(m_collapsedFeetAngle), collapseSpeed, deltaTime); } */ } } else { if (!m_collapsed) { Collapsed(true); } } } if (IsPowered() && !IsCollapsed()) { // "normal" legs control here bool bStartComplete = (m_startComplete > 1.5f); float adaptionSpeed = IsCollapsing() ? 0.8f : 1.5f; int t = 0; for (TThrusters::iterator iter=m_vecThrusters.begin(); iter!=m_vecThrusters.end(); ++iter) { SThruster* pThruster = *iter; ++t; if (pThruster->heightAdaption > 0.f && bStartComplete && pThruster->pPart && pThruster->pParentPart) { const char* footName = pThruster->pPart->GetName().c_str(); EWarriorMovement mode = eWM_Hovering; float correction = 0.f, maxCorrection = 0.f; // adjust legs float error = 0.f; if (!pThruster->hit) error = pThruster->hoverHeight; // when not hit, correct downwards else if (pThruster->prevDist > 0.f) error = pThruster->prevDist - pThruster->hoverHeight; if (mode != eWM_None && abs(error) > 0.05f) { float speed = max(0.1f, min(1.f, abs(error))) * adaptionSpeed; correction = -sgn(error) * min(speed*deltaTime, abs(error)); // correct up to error // don't correct more than heightAdaption allows maxCorrection = abs((pThruster->heightInitial + sgn(correction)*pThruster->heightAdaption) - pThruster->pos.z); float minCorrection = (pThruster->groundContact) ? 0.f : -maxCorrection; correction = CLAMP(correction, minCorrection, maxCorrection); if (abs(correction) > 0.0001f) { // positive correction for leg, negative for foot Matrix34 legLocal = pThruster->pParentPart->GetLocalBaseTM(); Matrix34 footLocal = pThruster->pPart->GetLocalBaseTM(); float radius = footLocal.GetTranslation().len(); float deltaAngle = correction / radius; // this assumes correction on circle (accurate enough for large radius) Matrix34 legTM = Matrix33(legLocal) * Matrix33::CreateRotationX(deltaAngle); Matrix34 footTM = Matrix33(footLocal) * Matrix33::CreateRotationX(-deltaAngle); legTM.SetTranslation(legLocal.GetTranslation()); footTM.SetTranslation(footLocal.GetTranslation()); pThruster->pParentPart->SetLocalBaseTM(legTM); pThruster->pPart->SetLocalBaseTM(footTM); } } if (IsProfilingMovement()) { static ICVar* pDebugLeg = GetISystem()->GetIConsole()->GetCVar("warrior_debug_leg"); if (pDebugLeg && pDebugLeg->GetIVal() == t) { //CryLog("hoverErr %.2f, levelErr %.2f, neutralErr %.2f -> %s corr %.3f (max %.2f)", hoverError, levelError, neutralError, sMode, correction, maxCorrection); } } } } } // regain control if (m_collapseTimer > m_recoverTime) { Collapsed(false); } for (TThrusters::iterator it=m_vecThrusters.begin(); it!=m_vecThrusters.end(); ++it) { (*it)->groundContact = false; } }
bool CIntersectionAssistanceUnit::GetHighestScoringLastKnownGoodPosition( const QuatT& baseOrientation, QuatT& outQuat ) const { bool bFlippedIsBest = false; if(!m_lastKnownGoodPositions.empty()) { // Higher is better float fBestScore = 0.0f; int bestIndex = -1; Vec3 vBaseUpDir = baseOrientation.q.GetColumn2().GetNormalized(); for(uint8 i = 0; i < m_lastKnownGoodPositions.size(); ++i) { const QuatT& qLastKnownGood = m_lastKnownGoodPositions[i]; if(IsPositionWithinAcceptedLimits(qLastKnownGood.t, baseOrientation.t, kDistanceTolerance)) { // Generate [0.0f,1.0f] score for distance const Vec3 distVec = (qLastKnownGood.t - baseOrientation.t); const float length = max(distVec.GetLengthFast(),0.0001f); const float distanceScore = max(1.0f - (length * kInverseDistanceTolerance) * kDistanceWeight, 0.0f); Vec3 vUpDir = qLastKnownGood.q.GetColumn2(); const float regularOrientationScore = vBaseUpDir.Dot(vUpDir); const float flippedOrientationScore = vBaseUpDir.Dot(-vUpDir); float orientationScore = max(regularOrientationScore, flippedOrientationScore); orientationScore *= kOrientationWeight; const float fCandidateScore = distanceScore + orientationScore; #ifndef _RELEASE if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled == 2) { CryWatch("[INDEX(%d)] : D[%.3f] O[%.3f] T[%.3f] (%s)", i, distanceScore, orientationScore, fCandidateScore, flippedOrientationScore > regularOrientationScore ? "*F*" : "R"); } #endif //#ifndef _RELEASE if(fCandidateScore > fBestScore) { bestIndex = i; fBestScore = fCandidateScore; bFlippedIsBest = (flippedOrientationScore > regularOrientationScore); } } } if(bestIndex >= 0) { outQuat = m_lastKnownGoodPositions[bestIndex]; if(bFlippedIsBest) { Matrix34 wMat(outQuat); Vec3 vFlippedUpDir = -outQuat.q.GetColumn2().GetNormalized(); Vec3 vForwardDir = outQuat.q.GetColumn1().GetNormalized(); Vec3 vSideDir = -outQuat.q.GetColumn0().GetNormalized(); Matrix34 wFlippedMat; wFlippedMat = Matrix34::CreateFromVectors(vSideDir, vForwardDir, vFlippedUpDir, wMat.GetTranslation()); outQuat = QuatT(wFlippedMat); // Adjust pos (rotating around OOBB centre effectively) const IEntity* pSubjectEntity = gEnv->pEntitySystem->GetEntity(m_subjectEntityId); if(pSubjectEntity) { AABB entAABB; OBB entOBB; pSubjectEntity->GetLocalBounds(entAABB); entOBB.SetOBBfromAABB(Quat(IDENTITY), entAABB); Vec3 Centre = wMat.TransformPoint(entOBB.c); Vec3 toCentre = Centre - outQuat.t; outQuat.t += (toCentre * 2.0f); } } #ifndef _RELEASE if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled == 2) { m_currentBestIndex = bestIndex; CryWatch("[BEST INDEX] : %d", bestIndex); } #endif // ifndef _RELEASE return true; } } #ifndef _RELEASE m_currentBestIndex = -1; #endif // ifndef _RELEASE return false; }
void ElasticFoundationForceImpl::processContact (const State& state, ContactSurfaceIndex meshIndex, ContactSurfaceIndex otherBodyIndex, const Parameters& param, const std::set<int>& insideFaces, Real areaScale, Vector_<SpatialVec>& bodyForces, Real& pe) const { const ContactGeometry& otherObject = subsystem.getBodyGeometry(set, otherBodyIndex); const MobilizedBody& body1 = subsystem.getBody(set, meshIndex); const MobilizedBody& body2 = subsystem.getBody(set, otherBodyIndex); const Transform t1g = body1.getBodyTransform(state)*subsystem.getBodyTransform(set, meshIndex); // mesh to ground const Transform t2g = body2.getBodyTransform(state)*subsystem.getBodyTransform(set, otherBodyIndex); // other object to ground const Transform t12 = ~t2g*t1g; // mesh to other object // Loop over all the springs, and evaluate the force from each one. for (std::set<int>::const_iterator iter = insideFaces.begin(); iter != insideFaces.end(); ++iter) { int face = *iter; UnitVec3 normal; bool inside; Vec3 nearestPoint = otherObject.findNearestPoint(t12*param.springPosition[face], inside, normal); if (!inside) continue; // Find how much the spring is displaced. nearestPoint = t2g*nearestPoint; const Vec3 springPosInGround = t1g*param.springPosition[face]; const Vec3 displacement = nearestPoint-springPosInGround; const Real distance = displacement.norm(); if (distance == 0.0) continue; const Vec3 forceDir = displacement/distance; // Calculate the relative velocity of the two bodies at the contact point. const Vec3 station1 = body1.findStationAtGroundPoint(state, nearestPoint); const Vec3 station2 = body2.findStationAtGroundPoint(state, nearestPoint); const Vec3 v1 = body1.findStationVelocityInGround(state, station1); const Vec3 v2 = body2.findStationVelocityInGround(state, station2); const Vec3 v = v2-v1; const Real vnormal = dot(v, forceDir); const Vec3 vtangent = v-vnormal*forceDir; // Calculate the damping force. const Real area = areaScale * param.springArea[face]; const Real f = param.stiffness*area*distance*(1+param.dissipation*vnormal); Vec3 force = (f > 0 ? f*forceDir : Vec3(0)); // Calculate the friction force. const Real vslip = vtangent.norm(); if (f > 0 && vslip != 0) { const Real vrel = vslip/transitionVelocity; const Real ffriction = f*(std::min(vrel, Real(1)) *(param.dynamicFriction+2*(param.staticFriction-param.dynamicFriction) /(1+vrel*vrel))+param.viscousFriction*vslip); force += ffriction*vtangent/vslip; } body1.applyForceToBodyPoint(state, station1, force, bodyForces); body2.applyForceToBodyPoint(state, station2, -force, bodyForces); pe += param.stiffness*area*displacement.normSqr()/2; } }
void testEwaldPME(bool includeExceptions) { // Use amorphous NaCl system for the tests const int numParticles = 894; const double cutoff = 1.2; const double boxSize = 3.00646; double tol = 1e-5; ReferencePlatform reference; System system; NonbondedForce* nonbonded = new NonbondedForce(); nonbonded->setNonbondedMethod(NonbondedForce::Ewald); nonbonded->setCutoffDistance(cutoff); nonbonded->setEwaldErrorTolerance(tol); for (int i = 0; i < numParticles/2; i++) system.addParticle(22.99); for (int i = 0; i < numParticles/2; i++) system.addParticle(35.45); for (int i = 0; i < numParticles/2; i++) nonbonded->addParticle(1.0, 1.0,0.0); for (int i = 0; i < numParticles/2; i++) nonbonded->addParticle(-1.0, 1.0,0.0); system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize)); system.addForce(nonbonded); vector<Vec3> positions(numParticles); #include "nacl_amorph.dat" if (includeExceptions) { // Add some exclusions. for (int i = 0; i < numParticles-1; i++) { Vec3 delta = positions[i]-positions[i+1]; if (sqrt(delta.dot(delta)) < 0.5*cutoff) nonbonded->addException(i, i+1, i%2 == 0 ? 0.0 : 0.5, 1.0, 0.0); } } // (1) Check whether the Reference and CPU platforms agree when using Ewald Method VerletIntegrator integrator1(0.01); VerletIntegrator integrator2(0.01); Context cpuContext(system, integrator1, platform); Context referenceContext(system, integrator2, reference); cpuContext.setPositions(positions); referenceContext.setPositions(positions); State cpuState = cpuContext.getState(State::Forces | State::Energy); State referenceState = referenceContext.getState(State::Forces | State::Energy); tol = 1e-2; for (int i = 0; i < numParticles; i++) { ASSERT_EQUAL_VEC(referenceState.getForces()[i], cpuState.getForces()[i], tol); } tol = 1e-5; ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cpuState.getPotentialEnergy(), tol); // (2) Check whether Ewald method in CPU is self-consistent double norm = 0.0; for (int i = 0; i < numParticles; ++i) { Vec3 f = cpuState.getForces()[i]; norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; } norm = std::sqrt(norm); const double delta = 5e-3; double step = delta/norm; for (int i = 0; i < numParticles; ++i) { Vec3 p = positions[i]; Vec3 f = cpuState.getForces()[i]; positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); } VerletIntegrator integrator3(0.01); Context cpuContext2(system, integrator3, platform); cpuContext2.setPositions(positions); tol = 1e-2; State cpuState2 = cpuContext2.getState(State::Energy); ASSERT_EQUAL_TOL(norm, (cpuState2.getPotentialEnergy()-cpuState.getPotentialEnergy())/delta, tol) // (3) Check whether the Reference and CPU platforms agree when using PME nonbonded->setNonbondedMethod(NonbondedForce::PME); cpuContext.reinitialize(); referenceContext.reinitialize(); cpuContext.setPositions(positions); referenceContext.setPositions(positions); cpuState = cpuContext.getState(State::Forces | State::Energy); referenceState = referenceContext.getState(State::Forces | State::Energy); tol = 1e-2; for (int i = 0; i < numParticles; i++) { ASSERT_EQUAL_VEC(referenceState.getForces()[i], cpuState.getForces()[i], tol); } tol = 1e-5; ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cpuState.getPotentialEnergy(), tol); // (4) Check whether PME method in CPU is self-consistent norm = 0.0; for (int i = 0; i < numParticles; ++i) { Vec3 f = cpuState.getForces()[i]; norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; } norm = std::sqrt(norm); step = delta/norm; for (int i = 0; i < numParticles; ++i) { Vec3 p = positions[i]; Vec3 f = cpuState.getForces()[i]; positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step); } VerletIntegrator integrator4(0.01); Context cpuContext3(system, integrator4, platform); cpuContext3.setPositions(positions); tol = 1e-2; State cpuState3 = cpuContext3.getState(State::Energy); ASSERT_EQUAL_TOL(norm, (cpuState3.getPotentialEnergy()-cpuState.getPotentialEnergy())/delta, tol) }
//------------------------------------------- void CGameRules::ProcessClientExplosionScreenFX(const ExplosionInfo &explosionInfo) { IActor *pClientActor = g_pGame->GetIGameFramework()->GetClientActor(); if (pClientActor) { //Distance float dist = (pClientActor->GetEntity()->GetWorldPos() - explosionInfo.pos).len(); //Is the explosion in Player's FOV (let's suppose the FOV a bit higher, like 80) CActor *pActor = (CActor *)pClientActor; SMovementState state; if (IMovementController *pMV = pActor->GetMovementController()) { pMV->GetMovementState(state); } Vec3 eyeToExplosion = explosionInfo.pos - state.eyePosition; eyeToExplosion.Normalize(); bool inFOV = (state.eyeDirection.Dot(eyeToExplosion) > 0.68f); // if in a vehicle eyeDirection is wrong if(pActor && pActor->GetLinkedVehicle()) { Vec3 eyeDir = static_cast<CPlayer*>(pActor)->GetVehicleViewDir(); inFOV = (eyeDir.Dot(eyeToExplosion) > 0.68f); } //All explosions have radial blur (default 30m radius, to make Sean happy =)) float maxBlurDistance = (explosionInfo.maxblurdistance>0.0f)?explosionInfo.maxblurdistance:30.0f; if (maxBlurDistance>0.0f && g_pGameCVars->g_radialBlur>0.0f && m_explosionScreenFX && explosionInfo.radius>0.5f) { if (inFOV && dist < maxBlurDistance) { ray_hit hit; int col = gEnv->pPhysicalWorld->RayWorldIntersection(explosionInfo.pos , -eyeToExplosion*dist, ent_static | ent_terrain, rwi_stop_at_pierceable|rwi_colltype_any, &hit, 1); //If there was no obstacle between flashbang grenade and player if(!col) { float blurRadius = (-1.0f/maxBlurDistance)*dist + 1.0f; gEnv->p3DEngine->SetPostEffectParam("FilterRadialBlurring_Radius", blurRadius); gEnv->p3DEngine->SetPostEffectParam("FilterRadialBlurring_Amount", 1.0f); //CActor *pActor = (CActor *)pClientActor; if (pActor->GetScreenEffects() != 0) { CPostProcessEffect *pBlur = new CPostProcessEffect(pClientActor->GetEntityId(),"FilterRadialBlurring_Amount", 0.0f); CLinearBlend *pLinear = new CLinearBlend(1.0f); pActor->GetScreenEffects()->StartBlend(pBlur, pLinear, 1.0f, 98); pActor->GetScreenEffects()->SetUpdateCoords("FilterRadialBlurring_ScreenPosX","FilterRadialBlurring_ScreenPosY", explosionInfo.pos); } float distAmp = 1.0f - (dist / maxBlurDistance); if (gEnv->pInput) gEnv->pInput->ForceFeedbackEvent( SFFOutputEvent(eDI_XI, eFF_Rumble_Basic, 0.5f, distAmp*3.0f, 0.0f)); } } } //Flashbang effect if(dist<explosionInfo.radius && inFOV && (!strcmp(explosionInfo.effect_class,"flashbang") || !strcmp(explosionInfo.effect_class,"FlashbangAI"))) { ray_hit hit; int col = gEnv->pPhysicalWorld->RayWorldIntersection(explosionInfo.pos , -eyeToExplosion*dist, ent_static | ent_terrain, rwi_stop_at_pierceable|rwi_colltype_any, &hit, 1); //If there was no obstacle between flashbang grenade and player if(!col) { float power = explosionInfo.flashbangScale; power *= max(0.0f, 1 - (dist/explosionInfo.radius)); float lookingAt = (eyeToExplosion.Dot(state.eyeDirection.normalize()) + 1)*0.5f; power *= lookingAt; SAFE_HUD_FUNC(OnFlashbang(1.0f + (power * 4), explosionInfo.blindAmount)); SAFE_SOUNDMOODS_FUNC(AddSoundMood(SOUNDMOOD_EXPLOSION,MIN(power*40.0f,100.0f))); gEnv->p3DEngine->SetPostEffectParam("Flashbang_Time", 1.0f + (power * 4)); gEnv->p3DEngine->SetPostEffectParam("FlashBang_BlindAmount",explosionInfo.blindAmount); gEnv->p3DEngine->SetPostEffectParam("Flashbang_DifractionAmount", (power * 2)); gEnv->p3DEngine->SetPostEffectParam("Flashbang_Active", 1); } } else if(inFOV && (dist < explosionInfo.radius)) { if (explosionInfo.damage>10.0f || explosionInfo.pressure>100.0f) { //Add some angular impulse to the client actor depending on distance, direction... float dt = (1.0f - dist/explosionInfo.radius); dt = dt * dt; float angleZ = g_PI*0.15f*dt; float angleX = g_PI*0.15f*dt; pActor->AddAngularImpulse(Ang3(Random(-angleX*0.5f,angleX),0.0f,Random(-angleZ,angleZ)),0.0f,dt*2.0f); } } float fDist2=(pClientActor->GetEntity()->GetWorldPos()-explosionInfo.pos).len2(); if (fDist2<250.0f*250.0f) { SAFE_HUD_FUNC(ShowSoundOnRadar(explosionInfo.pos, explosionInfo.hole_size)); if (fDist2<sqr(SAFE_HUD_FUNC_RET(GetBattleRange()))) SAFE_HUD_FUNC(TickBattleStatus(1.0f)); } } }
void SoundD3D::Localize() { #ifdef DIRECT_SOUND_3D if (sound3d) { sound3d->SetMinDistance(min_dist, DS3D_IMMEDIATE); sound3d->SetMaxDistance(max_dist, DS3D_IMMEDIATE); sound3d->SetPosition(location.x, location.y, location.z, DS3D_IMMEDIATE); sound3d->SetVelocity(velocity.x, velocity.y, velocity.z, DS3D_IMMEDIATE); } #else // if no buffer, nothing to do: if (!buffer) { moved = false; return; } // Compute pan and volume from scratch: if ((flags & LOC_3D) && creator) { Vec3 loc = location; SoundCardD3D* ears = (SoundCardD3D*) creator; Camera& listener = ears->listener; Vec3 ear_loc = listener.Pos(); ear_loc.SwapYZ(); Vec3 direction = loc - ear_loc; loc.x = direction * listener.vrt(); loc.y = direction * listener.vup(); loc.z = direction * listener.vpn(); double pan = 10000; if (loc.z != 0.0f) pan = fabs(1000.0f * loc.x / loc.z); if (pan > 10000) pan = 10000; if (loc.x < 0) pan = -pan; if (volume > 0) volume = 0; double vol = volume; double mind2 = min_dist * min_dist; double maxd2 = max_dist * max_dist; double d2 = (loc.x*loc.x) + (loc.y*loc.y) + (loc.z*loc.z); if (d2 > maxd2) vol = -10000; else if (d2 > mind2) vol -= (d2-mind2)/(maxd2-mind2) * (vol+10000); // clamp volume to legal range: if (vol < -10000) vol = -10000; else if (vol > volume) vol = volume; /*** Print("Localize: ears = (%f, %f, %f)\n", ear_loc.x, ear_loc.y, ear_loc.z); Print(" world = (%f, %f, %f)\n", location.x, location.y, location.z); Print(" view = (%f, %f, %f)\n", loc.x, loc.y, loc.z); Print(" Pan=%f Volume=%f\n", pan, vol); /***/ HRESULT hr = buffer->SetPan((LONG) pan); if (!SUCCEEDED(hr)) { char warn[512]; sprintf_s(warn, "Warning could not set pan on buffer to %f", pan); SoundD3DError(warn, hr); } hr = buffer->SetVolume((LONG) vol); if (!SUCCEEDED(hr)) { char warn[512]; sprintf_s(warn, "Warning: could not set volume on buffer to %f", vol); SoundD3DError(warn, hr); } // if not too far to hear... if ((flags & DOPPLER) && (d2 < maxd2)) { // COMPUTE DOPPLER SHIFT: const float c = 10000.0f; direction.Normalize(); float v_L = ears->velocity * direction; float v_S = velocity * direction; DWORD f_shift = wfex.nSamplesPerSec; if (v_L != v_S) { // towards listener: if (v_S < 0) f_shift = wfex.nSamplesPerSec + 20; else f_shift = wfex.nSamplesPerSec - 20; } // distance rolloff of high frequencies: double dist = sqrt(d2); DWORD roll_off = (DWORD) (80 * dist/max_dist); f_shift -= roll_off; if (f_shift < 100) f_shift = 100; if (f_shift > 100000) f_shift = 100000; hr = buffer->SetFrequency(f_shift); if (!SUCCEEDED(hr)) { char warn[512]; sprintf_s(warn, "Warning: could not set Doppler frequency on buffer to %d", f_shift); //-V576 SoundD3DError(warn, hr); } } } else { buffer->SetPan((LONG) location.x); buffer->SetVolume((LONG) volume); } #endif moved = false; }
void testErrorTolerance(NonbondedForce::NonbondedMethod method) { // Create a cloud of random point charges. const int numParticles = 51; const double boxWidth = 5.0; System system; system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth)); NonbondedForce* force = new NonbondedForce(); system.addForce(force); vector<Vec3> positions(numParticles); OpenMM_SFMT::SFMT sfmt; init_gen_rand(0, sfmt); for (int i = 0; i < numParticles; i++) { system.addParticle(1.0); force->addParticle(-1.0+i*2.0/(numParticles-1), 1.0, 0.0); positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt)); } force->setNonbondedMethod(method); // For various values of the cutoff and error tolerance, see if the actual error is reasonable. for (double cutoff = 1.0; cutoff < boxWidth/2; cutoff *= 1.2) { force->setCutoffDistance(cutoff); vector<Vec3> refForces; double norm = 0.0; for (double tol = 5e-5; tol < 1e-3; tol *= 2.0) { force->setEwaldErrorTolerance(tol); VerletIntegrator integrator(0.01); Context context(system, integrator, platform); context.setPositions(positions); State state = context.getState(State::Forces); if (refForces.size() == 0) { refForces = state.getForces(); for (int i = 0; i < numParticles; i++) norm += refForces[i].dot(refForces[i]); norm = sqrt(norm); } else { double diff = 0.0; for (int i = 0; i < numParticles; i++) { Vec3 delta = refForces[i]-state.getForces()[i]; diff += delta.dot(delta); } diff = sqrt(diff)/norm; ASSERT(diff < 2*tol); } if (method == NonbondedForce::PME) { // See if the PME parameters were calculated correctly. double expectedAlpha, actualAlpha; int expectedSize[3], actualSize[3]; NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]); force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]); ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5); for (int i = 0; i < 3; i++) { ASSERT(actualSize[i] >= expectedSize[i]); ASSERT(actualSize[i] < expectedSize[i]+10); } } } } }
Mat4::Mat4(Vec3 a, double r) { // Create a rotation matrix for an arbitrary axis. // See Wikipedia or whatever for the formulae. double cosR = cos(r); double sinR = sin(r); m[0] = cosR + a.x() * a.x() * (1 - cosR); m[1] = a.y() * a.x() * (1 - cosR) + a.z() * sinR; m[2] = a.z() * a.x() * (1 - cosR) - a.y() * sinR; m[3] = 0; m[4] = a.x() * a.y() * (1 - cosR) - a.z() * sinR; m[5] = cosR + a.y() * a.y() * (1 - cosR); m[6] = a.z() * a.y() * (1 - cosR) + a.x() * sinR; m[7] = 0; m[8] = a.x() * a.z() * (1 - cosR) + a.y() * sinR; m[9] = a.y() * a.z() * (1 - cosR) - a.x() * sinR; m[10] = cosR + a.z() * a.z() * (1 - cosR); m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; }
// Dot product double Vec3::dot(Vec3& o) { return x() * o.x() + y() * o.y() + z() * o.z(); }
/** Actually reads in the data from the xml file. * \param root Root of the xml tree. */ void KartProperties::getAllData(const XMLNode * root) { root->get("version", &m_version); root->get("name", &m_name ); root->get("icon-file", &m_icon_file ); root->get("minimap-icon-file", &m_minimap_icon_file); root->get("shadow-file", &m_shadow_file ); Vec3 c; root->get("rgb", &c ); m_color.set(255, (int)(255*c.getX()), (int)(255*c.getY()), (int)(255*c.getZ())); root->get("groups", &m_groups ); root->get("random-wheel-rot", &m_has_rand_wheels ); root->get("shadow-scale", &m_shadow_scale ); root->get("shadow-x-offset", &m_shadow_x_offset ); root->get("shadow-y-offset", &m_shadow_y_offset ); root->get("type", &m_kart_type ); if(const XMLNode *dimensions_node = root->getNode("center")) dimensions_node->get("gravity-shift", &m_gravity_center_shift); if(const XMLNode *ai_node = root->getNode("ai")) { const XMLNode *easy = ai_node->getNode("easy"); m_ai_properties[RaceManager::DIFFICULTY_EASY]->load(easy); const XMLNode *medium = ai_node->getNode("medium"); m_ai_properties[RaceManager::DIFFICULTY_MEDIUM]->load(medium); const XMLNode *hard = ai_node->getNode("hard"); m_ai_properties[RaceManager::DIFFICULTY_HARD]->load(hard); const XMLNode *best = ai_node->getNode("best"); m_ai_properties[RaceManager::DIFFICULTY_BEST]->load(best); } if(const XMLNode *suspension_node = root->getNode("suspension")) { suspension_node->get("stiffness", &m_suspension_stiffness); suspension_node->get("rest", &m_suspension_rest ); suspension_node->get("travel-cm", &m_suspension_travel_cm); suspension_node->get("exp-spring-response", &m_exp_spring_response ); suspension_node->get("max-force", &m_max_suspension_force); } if(const XMLNode *wheels_node = root->getNode("wheels")) { wheels_node->get("damping-relaxation", &m_wheel_damping_relaxation ); wheels_node->get("damping-compression", &m_wheel_damping_compression); wheels_node->get("radius", &m_wheel_radius ); } if(const XMLNode *speed_weighted_objects_node = root->getNode("speed-weighted-objects")) { m_speed_weighted_object_properties.loadFromXMLNode(speed_weighted_objects_node); } if(const XMLNode *friction_node = root->getNode("friction")) friction_node->get("slip", &m_friction_slip); if(const XMLNode *stability_node = root->getNode("stability")) { stability_node->get("roll-influence", &m_roll_influence ); stability_node->get("chassis-linear-damping", &m_chassis_linear_damping ); stability_node->get("chassis-angular-damping", &m_chassis_angular_damping); stability_node->get("downward-impulse-factor", &m_downward_impulse_factor); stability_node->get("track-connection-accel", &m_track_connection_accel ); } if(const XMLNode *collision_node = root->getNode("collision")) { collision_node->get("impulse", &m_collision_impulse ); collision_node->get("impulse-time", &m_collision_impulse_time ); collision_node->get("terrain-impulse", &m_collision_terrain_impulse); collision_node->get("restitution", &m_restitution ); collision_node->get("bevel-factor", &m_bevel_factor ); std::string s; collision_node->get("impulse-type", &s ); s = StringUtils::toLowerCase(s); if(s=="none") m_terrain_impulse_type = IMPULSE_NONE; else if(s=="normal") m_terrain_impulse_type = IMPULSE_NORMAL; else if(s=="driveline") m_terrain_impulse_type = IMPULSE_TO_DRIVELINE; else { Log::fatal("[KartProperties]", "Missing or incorrect value for impulse-type: '%s'.", s.c_str()); } } //TODO: wheel front right and wheel front left is not loaded, yet is //TODO: listed as an attribute in the xml file after wheel-radius //TODO: same goes for their rear equivalents if(const XMLNode *jump_node= root->getNode("jump")) { jump_node->get("animation-time", &m_jump_animation_time); } if(const XMLNode *camera_node= root->getNode("camera")) { camera_node->get("distance", &m_camera_distance); camera_node->get("forward-up-angle", &m_camera_forward_up_angle); m_camera_forward_up_angle *= DEGREE_TO_RAD; camera_node->get("backward-up-angle", &m_camera_backward_up_angle); m_camera_backward_up_angle *= DEGREE_TO_RAD; } if(const XMLNode *sounds_node= root->getNode("sounds")) { std::string s; sounds_node->get("engine", &s); if (s == "large") m_engine_sfx_type = "engine_large"; else if (s == "small") m_engine_sfx_type = "engine_small"; else { if (sfx_manager->soundExist(s)) { m_engine_sfx_type = s; } else { Log::error("[KartProperties]", "Kart '%s' has an invalid engine '%s'.", m_name.c_str(), s.c_str()); m_engine_sfx_type = "engine_small"; } } #ifdef WILL_BE_ENABLED_ONCE_DONE_PROPERLY // Load custom kart SFX files (TODO: enable back when it's implemented properly) for (int i = 0; i < SFXManager::NUM_CUSTOMS; i++) { std::string tempFile; // Get filename associated with each custom sfx tag in sfx config if (sounds_node->get(sfx_manager->getCustomTagName(i), tempFile)) { // determine absolute filename // FIXME: will not work with add-on packs (is data dir the same)? tempFile = file_manager->getKartFile(tempFile, getIdent()); // Create sfx in sfx manager and store id m_custom_sfx_id[i] = sfx_manager->addSingleSfx(tempFile, 1, 0.2f,1.0f); } else { // if there is no filename associated with a given tag m_custom_sfx_id[i] = -1; } // if custom sound } // for i<SFXManager::NUM_CUSTOMS #endif } // if sounds-node exist if(const XMLNode *nitro_node = root->getNode("nitro")) { nitro_node->get("consumption", &m_nitro_consumption ); nitro_node->get("small-container", &m_nitro_small_container ); nitro_node->get("big-container", &m_nitro_big_container ); nitro_node->get("max-speed-increase", &m_nitro_max_speed_increase); nitro_node->get("engine-force", &m_nitro_engine_force ); nitro_node->get("duration", &m_nitro_duration ); nitro_node->get("fade-out-time", &m_nitro_fade_out_time ); nitro_node->get("max", &m_nitro_max ); nitro_node->get("min-consumption-time", &m_nitro_min_consumption ); } if(const XMLNode *bubble_node = root->getNode("bubblegum")) { bubble_node->get("time", &m_bubblegum_time ); bubble_node->get("speed-fraction", &m_bubblegum_speed_fraction); bubble_node->get("fade-in-time", &m_bubblegum_fade_in_time ); bubble_node->get("torque", &m_bubblegum_torque ); } if(const XMLNode *rescue_node = root->getNode("rescue")) { rescue_node->get("vert-offset", &m_rescue_vert_offset); rescue_node->get("time", &m_rescue_time ); rescue_node->get("height", &m_rescue_height ); } if(const XMLNode *explosion_node = root->getNode("explosion")) { explosion_node->get("time", &m_explosion_time ); explosion_node->get("radius", &m_explosion_radius); explosion_node->get("invulnerability-time", &m_explosion_invulnerability_time); } if(const XMLNode *skid_node = root->getNode("skid")) { m_skidding_properties->load(skid_node); } if(const XMLNode *slipstream_node = root->getNode("slipstream")) { slipstream_node->get("length", &m_slipstream_length ); slipstream_node->get("width", &m_slipstream_width ); slipstream_node->get("collect-time", &m_slipstream_collect_time ); slipstream_node->get("use-time", &m_slipstream_use_time ); slipstream_node->get("add-power", &m_slipstream_add_power ); slipstream_node->get("min-speed", &m_slipstream_min_speed ); slipstream_node->get("max-speed-increase", &m_slipstream_max_speed_increase); slipstream_node->get("duration", &m_slipstream_duration ); slipstream_node->get("fade-out-time",&m_slipstream_fade_out_time ); } if(const XMLNode *turn_node = root->getNode("turn")) { turn_node->get("time-full-steer", &m_time_full_steer ); turn_node->get("time-reset-steer", &m_time_reset_steer ); turn_node->get("turn-radius", &m_turn_angle_at_speed ); // For now store the turn radius in turn angle, the correct // value can only be determined later in ::load } if(const XMLNode *engine_node = root->getNode("engine")) { engine_node->get("brake-factor", &m_brake_factor); engine_node->get("max-speed-reverse-ratio", &m_max_speed_reverse_ratio); engine_node->get("power", &m_engine_power); if(m_engine_power.size()!=RaceManager::DIFFICULTY_COUNT) { Log::fatal("[KartProperties]", "Incorrect engine-power specifications for kart '%s'", getIdent().c_str()); } engine_node->get("max-speed", &m_max_speed); if(m_max_speed.size()!=RaceManager::DIFFICULTY_COUNT) { Log::fatal("[KartProperties]", "Incorrect max-speed specifications for kart '%s'", getIdent().c_str()); } } // if getNode("engine") if(const XMLNode *gear_node = root->getNode("gear")) { gear_node->get("switch-ratio", &m_gear_switch_ratio ); gear_node->get("power-increase", &m_gear_power_increase); } if(const XMLNode *mass_node = root->getNode("mass")) mass_node->get("value", &m_mass); if(const XMLNode *plunger_node= root->getNode("plunger")) { plunger_node->get("band-max-length", &m_rubber_band_max_length ); plunger_node->get("band-force", &m_rubber_band_force ); plunger_node->get("band-duration", &m_rubber_band_duration ); plunger_node->get("band-speed-increase",&m_rubber_band_speed_increase); plunger_node->get("band-fade-out-time", &m_rubber_band_fade_out_time ); plunger_node->get("in-face-time", &m_plunger_in_face_duration); if(m_plunger_in_face_duration.size()!=RaceManager::DIFFICULTY_COUNT) { Log::fatal("KartProperties", "Invalid plunger in-face-time specification."); } } if(const XMLNode *zipper_node= root->getNode("zipper")) { zipper_node->get("time", &m_zipper_time ); zipper_node->get("fade-out-time", &m_zipper_fade_out_time ); zipper_node->get("force", &m_zipper_force ); zipper_node->get("speed-gain", &m_zipper_speed_gain ); zipper_node->get("max-speed-increase", &m_zipper_max_speed_increase); } if(const XMLNode *swatter_node= root->getNode("swatter")) { swatter_node->get("duration", &m_swatter_duration ); swatter_node->get("squash-duration", &m_squash_duration ); swatter_node->get("squash-slowdown", &m_squash_slowdown ); if(swatter_node->get("distance", &m_swatter_distance2) ) { // Avoid squaring if distance is not defined, so that // distance2 remains UNDEFINED (which is a negative value) m_swatter_distance2 *= m_swatter_distance2; } } if(const XMLNode *lean_node= root->getNode("lean")) { lean_node->get("max", &m_max_lean ); lean_node->get("speed", &m_lean_speed); m_max_lean *= DEGREE_TO_RAD; m_lean_speed *= DEGREE_TO_RAD; } if(const XMLNode *startup_node= root->getNode("startup")) { startup_node->get("time", &m_startup_times); startup_node->get("boost", &m_startup_boost); } if(m_kart_model) m_kart_model->loadInfo(*root); } // getAllData
void MovementController::OnUpdate(DWORD const deltaMilliseconds) { //if (m_bKey['Q']) //{ // // This code is a cheat to position the camera exactly in a given // // spot so I can take screen shots! // Mat4x4 camTranslate; // D3DXMatrixTranslation(&m_matPosition, 8.847f, 7.055f, 11.618f); // m_fTargetYaw = m_fYaw += -64.35f; // m_fTargetPitch = m_fPitch = 28.57f; // // Calculate the new rotation matrix from the camera // // yaw and pitch. // Mat4x4 matRot; // D3DXMatrixRotationYawPitchRoll(&matRot, DEGREES_TO_RADIANS(m_fYaw), DEGREES_TO_RADIANS(m_fPitch), 0); // // Create the new object-to-world matrix, and the // // new world-to-object matrix. // D3DXMatrixMultiply(&m_matToWorld, &matRot, &m_matPosition); // D3DXMatrixInverse(&m_matFromWorld, NULL, &m_matToWorld); // m_object->VSetTransform(&m_matToWorld, &m_matFromWorld); // return; //} bool bTranslating = false; Vec4 atWorld(0,0,0,0); Vec4 rightWorld(0,0,0,0); Vec4 upWorld(0,0,0,0); if (m_bKey['W'] || m_bKey['S']) { // In D3D, the "look at" default is always // the positive Z axis. Vec4 at = g_Forward4; if (m_bKey['S']) at *= -1; // This will give us the "look at" vector // in world space - we'll use that to move // the camera. atWorld = m_matToWorld.Xform(at); bTranslating = true; } if (m_bKey['A'] || m_bKey['D']) { // In D3D, the "right" default is always // the positive X axis. Vec4 right = g_Right4; if (m_bKey['A']) right *= -1; // This will give us the "right" vector // in world space - we'll use that to move // the camera rightWorld = m_matToWorld.Xform(right); bTranslating = true; } if (m_bKey[' '] || m_bKey['C'] || m_bKey['X']) { // In D3D, the "up" default is always // the positive Y axis. Vec4 up = g_Right4; if (!m_bKey[' ']) up *= -1; //Unlike strafing, Up is always up no matter //which way you are looking upWorld = up; bTranslating = true; } //Handling rotation as a result of mouse position { // The secret formula!!! Don't give it away! //If you are seeing this now, then you must be some kind of elite hacker! m_fYaw += (m_fTargetYaw - m_fYaw) * ( .35f ); m_fTargetPitch = MAX(-90, MIN(90, m_fTargetPitch)); m_fPitch += (m_fTargetPitch - m_fPitch) * ( .35f ); // Calculate the new rotation matrix from the camera // yaw and pitch. Mat4x4 matRot; matRot.BuildYawPitchRoll(DEGREES_TO_RADIANS(-m_fYaw), DEGREES_TO_RADIANS(m_fPitch), 0); // Create the new object-to-world matrix, and the // new world-to-object matrix. m_matToWorld = matRot * m_matPosition; m_matFromWorld = m_matToWorld.Inverse(); m_object->VSetTransform(&m_matToWorld, &m_matFromWorld); } if (bTranslating) { float elapsedTime = (float)deltaMilliseconds / 1000.0f; Vec3 direction = atWorld + rightWorld + upWorld; direction.Normalize(); // Ramp the acceleration by the elapsed time. float numberOfSeconds = 5.f; m_currentSpeed += m_maxSpeed * ( (elapsedTime*elapsedTime) / numberOfSeconds); if (m_currentSpeed > m_maxSpeed) m_currentSpeed = m_maxSpeed; direction *= m_currentSpeed; Vec3 pos = m_matPosition.GetPosition() + direction; m_matPosition.SetPosition(pos); m_matToWorld.SetPosition(pos); m_matFromWorld = m_matToWorld.Inverse(); m_object->VSetTransform(&m_matToWorld, &m_matFromWorld); } else { m_currentSpeed = 0.0f; } }
//--------------------------------------------------- void CGameRules::ProcessExplosionMaterialFX(const ExplosionInfo &explosionInfo) { // if an effect was specified, don't use MFX if (explosionInfo.pParticleEffect) return; // impact stuff here SMFXRunTimeEffectParams params; params.soundSemantic = eSoundSemantic_Explosion; params.pos = params.decalPos = explosionInfo.pos; params.trg = 0; params.trgRenderNode = 0; Vec3 gravity; pe_params_buoyancy buoyancy; gEnv->pPhysicalWorld->CheckAreas(params.pos, gravity, &buoyancy); // 0 for water, 1 for air Vec3 pos=params.pos; params.inWater = (buoyancy.waterPlane.origin.z > params.pos.z) && (gEnv->p3DEngine->GetWaterLevel(&pos)>=params.pos.z); params.inZeroG = (gravity.len2() < 0.0001f); params.trgSurfaceId = 0; static const int objTypes = ent_all; static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; ray_hit ray; if (explosionInfo.impact) { params.dir[0] = explosionInfo.impact_velocity.normalized(); params.normal = explosionInfo.impact_normal; if (gEnv->pPhysicalWorld->RayWorldIntersection(params.pos-params.dir[0]*0.0125f, params.dir[0]*0.25f, objTypes, flags, &ray, 1)) { params.trgSurfaceId = ray.surface_idx; if (ray.pCollider->GetiForeignData()==PHYS_FOREIGN_ID_STATIC) params.trgRenderNode = (IRenderNode*)ray.pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC); } } else { params.dir[0] = gravity; params.normal = -gravity.normalized(); if (gEnv->pPhysicalWorld->RayWorldIntersection(params.pos, gravity, objTypes, flags, &ray, 1)) { params.trgSurfaceId = ray.surface_idx; if (ray.pCollider->GetiForeignData()==PHYS_FOREIGN_ID_STATIC) params.trgRenderNode = (IRenderNode*)ray.pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC); } } string effectClass = explosionInfo.effect_class; if (effectClass.empty()) effectClass = "generic"; string query = effectClass + "_explode"; if(gEnv->p3DEngine->GetWaterLevel(&explosionInfo.pos)>explosionInfo.pos.z) query = query + "_underwater"; IMaterialEffects* pMaterialEffects = gEnv->pGame->GetIGameFramework()->GetIMaterialEffects(); TMFXEffectId effectId = pMaterialEffects->GetEffectId(query.c_str(), params.trgSurfaceId); if (effectId == InvalidEffectId) effectId = pMaterialEffects->GetEffectId(query.c_str(), pMaterialEffects->GetDefaultSurfaceIndex()); if (effectId != InvalidEffectId) pMaterialEffects->ExecuteEffect(effectId, params); }
//------------------------------------------------------------------------ float CGameRulesCommonDamageHandling::GetCollisionEnergy( const IEntity *pVictim, const CGameRules::SCollisionHitInfo& colHitInfo ) const { float m1 = colHitInfo.target_mass; float m0 = 0.f; IPhysicalEntity *phys = pVictim->GetPhysics(); if(phys) { pe_status_dynamics dyn; phys->GetStatus(&dyn); m0 = dyn.mass; } IEntity *pOffender = gEnv->pEntitySystem->GetEntity(colHitInfo.targetId); bool bCollider = (pOffender || m1 > 0.001f); const bool debugColl = DebugCollisions(); if (debugColl) { CryLog("GetCollisionEnergy %s (%.1f) <-> %s (%.1f)", pVictim?pVictim->GetName():"[no entity]", m0, pOffender?pOffender->GetName():"[no entity]", m1); } float v0Sq = 0.f, v1Sq = 0.f; if (bCollider) // non-static { m0 = min(m0, m1); Vec3 v0normal, v1normal, vrel; Vec3 tempNormal = colHitInfo.normal; float v0dotN = colHitInfo.velocity.dot(colHitInfo.normal); v0normal = tempNormal.scale(v0dotN); float v1dotN = colHitInfo.target_velocity.dot(colHitInfo.normal);; // "target" is the offender v1normal = tempNormal.scale(v1dotN); vrel = v0normal.sub(v1normal); float vrelSq = vrel.len2(); v0Sq = min( sqr(v0dotN), vrelSq ); v1Sq = min( sqr(v1dotN), vrelSq ); if (debugColl) { IPersistantDebug* pPD = g_pGame->GetIGameFramework()->GetIPersistantDebug(); pPD->Begin("CollDamage", false); pPD->AddSphere(colHitInfo.pos, 0.15f, Col_Red, 5.f); pPD->AddDirection(colHitInfo.pos, 1.5f, tempNormal.scale(sgn(v0dotN)), Col_Green, 5.f); pPD->AddDirection(colHitInfo.pos, 1.5f, tempNormal.scale(sgn(v1dotN)), Col_Red, 5.f); if ((v0Sq > 2*2) || (v1Sq > 2*2)) { CryLog("normal velocities: rel %.1f, <%s> %.1f / <%s> %.1f", sqrt(vrelSq), pVictim?pVictim->GetName():"none", v0dotN, pOffender?pOffender->GetName():"none", v1dotN); CryLog("target_type: %i, target_velocity: %.2f %.2f %.2f", colHitInfo.target_type, colHitInfo.target_velocity.x, colHitInfo.target_velocity.y, colHitInfo.target_velocity.z); } } } else { v0Sq = sqr(colHitInfo.velocity.dot(colHitInfo.normal)); if (debugColl && v0Sq>5*5) { IPersistantDebug* pPD = g_pGame->GetIGameFramework()->GetIPersistantDebug(); pPD->Begin("CollDamage", false); pPD->AddDirection(colHitInfo.pos, 1.5f, colHitInfo.normal, Col_Green, 5.f); string debugText; debugText.Format("z: %f", colHitInfo.velocity.z); pPD->Add2DText(debugText.c_str(), 1.5f, Col_White, 5.f); } } float colliderEnergyScale = 1.f; if (pVictim != NULL && pOffender != NULL) { if(IActor* pVictimActor = g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pVictim->GetId())) { colliderEnergyScale = !pVictimActor->IsPlayer() ? GetAIPlayerAgainstColliderEnergyScale(*pOffender) : GetPlayerAgainstColliderEnergyScale(*pOffender); if (debugColl) { CryLog("colliderEnergyScale: %.1f", colliderEnergyScale); } } } const float energy0 = 0.5f * m0 * v0Sq; const float energy1 = 0.5f * m1 * v1Sq * colliderEnergyScale; return energy0 + energy1; }
//------------------------------------------------------------------------ void CVehicleMovementVTOL::ProcessActions(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); UpdateDamages(deltaTime); UpdateEngine(deltaTime); m_velDamp = 0.25f; m_playerControls.ProcessActions(deltaTime); Limit(m_forwardAction, -1.0f, 1.0f); Limit(m_strafeAction, -1.0f, 1.0f); m_actionYaw = 0.0f; Vec3 worldPos = m_pEntity->GetWorldPos(); IPhysicalEntity *pPhysics = GetPhysics(); // get the current state // roll pitch + yaw Matrix34 worldTM = m_pRotorPart ? m_pRotorPart->GetWorldTM() : m_pEntity->GetWorldTM(); // if (m_pRotorPart) // worldTM = m_pRotorPart->GetWorldTM(); // else // worldTM = m_pEntity->GetWorldTM(); Vec3 specialPos = worldTM.GetTranslation(); Ang3 angles = Ang3::GetAnglesXYZ(Matrix33(worldTM)); Matrix33 tm; tm.SetRotationXYZ((angles)); // +ve pitch means nose up const float ¤tPitch = angles.x; // +ve roll means to the left const float ¤tRoll = angles.y; // +ve direction mean rotation anti-clockwise about the z axis - 0 means along y float currentDir = angles.z; const float maxPitchAngle = 60.0f; float pitchDeg = RAD2DEG(currentPitch); if (pitchDeg >= (maxPitchAngle * 0.75f)) { float mult = pitchDeg / (maxPitchAngle); if (mult > 1.0f && m_desiredPitch < 0.0f) { m_desiredPitch *= 0.0f; m_actionPitch *= 0.0f; m_desiredPitch += 0.2f * mult; } else if (m_desiredPitch < 0.0f) { m_desiredPitch *= (1.0f - mult); m_desiredPitch += 0.05f; } } else if (pitchDeg <= (-maxPitchAngle * 0.75f)) { float mult = abs(pitchDeg) / (maxPitchAngle); if (mult > 1.0f && m_desiredPitch > 0.0f) { m_desiredPitch *= 0.0f; m_actionPitch *= 0.0f; m_desiredPitch += 0.2f * mult; } else if (m_desiredPitch > 0.0f) { m_desiredPitch *= (1.0f - mult); m_desiredPitch -= 0.05f; } } if (currentRoll >= DEG2RAD(m_maxRollAngle * 0.7f) && m_desiredRoll > 0.001f) { float r = currentRoll / DEG2RAD(m_maxRollAngle); r = min(1.0f, r * 1.0f); r = 1.0f - r; m_desiredRoll *= r; m_desiredRoll = min(1.0f, m_desiredRoll); } else if (currentRoll <= DEG2RAD(-m_maxRollAngle * 0.7f) && m_desiredRoll < 0.001f) { float r = abs(currentRoll) / DEG2RAD(m_maxRollAngle); r = min(1.0f, r * 1.0f); r = 1.0f - r; m_desiredRoll *= r; m_desiredRoll = max(-1.0f, m_desiredRoll); } Vec3 currentFwdDir2D = m_currentFwdDir; currentFwdDir2D.z = 0.0f; currentFwdDir2D.NormalizeSafe(); Vec3 currentLeftDir2D(-currentFwdDir2D.y, currentFwdDir2D.x, 0.0f); Vec3 currentVel = m_PhysDyn.v; Vec3 currentVel2D = currentVel; currentVel2D.z = 0.0f; float currentHeight = worldPos.z; float currentFwdSpeed = currentVel.Dot(currentFwdDir2D); ProcessActions_AdjustActions(deltaTime); float inputMult = m_basicSpeedFraction; // desired things float turnDecreaseScale = m_yawDecreaseWithSpeed / (m_yawDecreaseWithSpeed + fabs(currentFwdSpeed)); Vec3 desired_vel2D = currentFwdDir2D * m_forwardAction * m_maxFwdSpeed * inputMult + currentLeftDir2D * m_strafeAction * m_maxLeftSpeed * inputMult; // calculate the angle changes Vec3 desiredVelChange2D = desired_vel2D - currentVel2D; float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength(); Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle); float goal = abs(m_desiredPitch) + abs(m_desiredRoll); goal *= 1.5f; Interpolate(m_playerAcceleration, goal, 0.25f, deltaTime); Limit(m_playerAcceleration, 0.0f, 5.0f); //static float g_angleLift = 4.0f; if (abs(m_liftAction) > 0.001f && abs(m_forwardAction) < 0.001) { // float pitch = RAD2DEG(currentPitch); if (m_liftPitchAngle < 0.0f && m_liftAction > 0.0f) { m_liftPitchAngle = 0.0f; } else if (m_liftPitchAngle > 0.0f && m_liftAction < 0.0f) { m_liftPitchAngle = 0.0f; } Interpolate(m_liftPitchAngle, 1.25f * m_liftAction, 0.75f, deltaTime); if (m_liftPitchAngle < 1.0f && m_liftPitchAngle > -1.0f) { m_desiredPitch += 0.05f * m_liftAction; } } else if (m_liftAction < 0.001f && abs(m_liftPitchAngle) > 0.001) { Interpolate(m_liftPitchAngle, 0.0f, 1.0f, deltaTime); m_desiredPitch += 0.05f * -m_liftPitchAngle; } /* todo else if (m_liftAction < -0.001f) { m_desiredPitch += min(0.0f, (DEG2RAD(-5.0f) - currentPitch)) * 0.5f * m_liftAction; }*/ if (!iszero(m_desiredPitch)) { m_actionPitch -= m_desiredPitch * m_pitchInputConst; Limit(m_actionPitch, -m_maxYawRate, m_maxYawRate); } float rollAccel = 1.0f; if (abs(currentRoll + m_desiredRoll) < abs(currentRoll)) { rollAccel *= 1.25f; } m_actionRoll += m_pitchActionPerTilt * m_desiredRoll * rollAccel * (m_playerAcceleration + 1.0f); Limit(m_actionRoll, -10.0f, 10.0f); Limit(m_actionPitch, -10.0f, 10.0f); // roll as we turn if (!m_strafeAction) { m_actionYaw += m_yawPerRoll * currentRoll; } if (abs(m_strafeAction) > 0.001f) { float side = 0.0f; side = min(1.0f, max(-1.0f, m_strafeAction)); float roll = DEG2RAD(m_extraRollForTurn * 0.25f * side) - (currentRoll); m_actionRoll += max(0.0f, abs(roll)) * side * 1.0f; } float relaxRollTolerance = 0.0f; if (abs(m_turnAction) > 0.01f || abs(m_PhysDyn.w.z) > DEG2RAD(3.0f)) { m_actionYaw += -m_turnAction * m_yawInputConst * GetDamageMult(); float side = 0.0f; if (abs(m_turnAction) > 0.01f) { side = min(1.0f, max(-1.0f, m_turnAction)); } float roll = DEG2RAD(m_extraRollForTurn * side) - (currentRoll); m_actionRoll += max(0.0f, abs(roll)) * side * m_rollForTurnForce; roll *= max(1.0f, abs(m_PhysDyn.w.z)); m_actionRoll += roll; Limit(m_actionYaw, -m_maxYawRate, m_maxYawRate); } m_desiredDir = currentDir; m_lastDir = currentDir; float boost = Boosting() ? m_boostMult : 1.0f; float liftActionMax = 1.0f; if (m_pAltitudeLimitVar) { float altitudeLimit = m_pAltitudeLimitVar->GetFVal(); if (!iszero(altitudeLimit)) { float altitudeLowerOffset; if (m_pAltitudeLimitLowerOffsetVar) { float r = 1.0f - min(1.0f, max(0.0f, m_pAltitudeLimitLowerOffsetVar->GetFVal())); altitudeLowerOffset = r * altitudeLimit; } else { altitudeLowerOffset = altitudeLimit; } float mult = 1.0f; if (currentHeight >= altitudeLimit) { if (m_liftAction > 0.f) { mult = 0.0f; } } else if (currentHeight >= altitudeLowerOffset) { float zone = altitudeLimit - altitudeLowerOffset; mult = (altitudeLimit - currentHeight) / (zone); } m_liftAction *= mult; if (currentPitch > DEG2RAD(0.0f)) { if (m_forwardAction > 0.0f) { m_forwardAction *= mult; } if (m_actionPitch > 0.0f) { m_actionPitch *= mult; m_actionPitch += -currentPitch; } } m_desiredHeight = min(altitudeLowerOffset, currentHeight); } } else { m_desiredHeight = currentHeight; } if (abs(m_liftAction) > 0.001f) { m_liftAction = min(liftActionMax, max(-0.2f, m_liftAction)); m_hoveringPower = (m_powerInputConst * m_liftAction) * boost; m_noHoveringTimer = 0.0f; } else if (!m_isTouchingGround) { if (m_noHoveringTimer <= 0.0f) { float gravity; pe_simulation_params paramsSim; if (pPhysics->GetParams(¶msSim)) { gravity = abs(paramsSim.gravity.z); } else { gravity = 9.2f; } float upDirZ = m_workingUpDir.z; if (abs(m_forwardAction) > 0.01 && upDirZ > 0.0f) { upDirZ = 1.0f; } else if (upDirZ > 0.8f) { upDirZ = 1.0f; } float upPower = upDirZ; upPower -= min(1.0f, abs(m_forwardAction) * abs(angles.x)); float turbulenceMult = 1.0f - min(m_turbulenceMultMax, m_turbulence); Vec3 &impulse = m_control.impulse; impulse += Vec3(0.0f, 0.0f, upPower) * gravity * turbulenceMult * GetDamageMult(); impulse.z -= m_PhysDyn.v.z * turbulenceMult; } else { m_noHoveringTimer -= deltaTime; } } if (m_pStabilizeVTOL) { float stabilizeTime = m_pStabilizeVTOL->GetFVal(); if (stabilizeTime > 0.0f) { if (m_relaxTimer < 6.0f) { m_relaxTimer += deltaTime; } else { float r = currentRoll - relaxRollTolerance; r = min(1.0f, max(-1.0f, r)); m_actionRoll += -r * m_relaxForce * (m_relaxTimer / 6.0f); } } } if (m_netActionSync.PublishActions( CNetworkMovementHelicopter(this) )) { m_pVehicle->GetGameObject()->ChangedNetworkState(eEA_GameClientDynamic); } }
bool CIntersectionAssistanceUnit::IsPositionWithinAcceptedLimits(const Vec3& vTestPos, const Vec3& vOrigin, const float fTolerance) const { const Vec3 vDiff = vTestPos - vOrigin; return (vDiff.GetLengthSquared() < (fTolerance * fTolerance)); }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementVTOL::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); if (!m_isVTOLMovement) { CVehicleMovementHelicopter::ProcessAI(deltaTime); return; } m_velDamp = 0.15f; const float maxDirChange = 15.0f; // it's useless to progress further if the engine has yet to be turned on if (!m_isEnginePowered) { return; } m_movementAction.Clear(); m_movementAction.isAI = true; ResetActions(); // Our current state const Vec3 worldPos = m_PhysPos.pos; const Matrix33 worldMat( m_PhysPos.q); Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat); const Vec3 currentVel = m_PhysDyn.v; const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f); // +ve direction mean rotation anti-clocwise about the z axis - 0 means along y float currentDir = worldAngles.z; // to avoid singularity const Vec3 vWorldDir = worldMat * FORWARD_DIRECTION; const Vec3 vWorldDir2D = Vec3( vWorldDir.x, vWorldDir.y, 0.0f ).GetNormalizedSafe(); // Our inputs const float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f; const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir; const Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D); const Vec3 desiredVel = desiredMoveDir * desiredSpeed; const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f); const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir; const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D); // Calculate the desired 2D velocity change Vec3 desiredVelChange2D = desiredVel2D - currentVel2D; float velChangeLength = desiredVelChange2D.GetLength2D(); bool isLandingMode = false; if (m_pLandingGears && m_pLandingGears->AreLandingGearsOpen()) { isLandingMode = true; } bool isHorizontal = (desiredSpeed >= 5.0f) && (desiredMoveDir.GetLength2D() > desiredMoveDir.z); float desiredPitch = 0.0f; float desiredRoll = 0.0f; float desiredDir = atan2f(-desiredLookDir2D.x, desiredLookDir2D.y); while (currentDir < desiredDir - gf_PI) { currentDir += 2.0f * gf_PI; } while (currentDir > desiredDir + gf_PI) { currentDir -= 2.0f * gf_PI; } float diffDir = (desiredDir - currentDir); m_actionYaw = diffDir * m_yawInputConst; m_actionYaw += m_yawInputDamping * (currentDir - m_lastDir) / deltaTime; m_lastDir = currentDir; if (isHorizontal && !isLandingMode) { float desiredFwdSpeed = desiredVelChange2D.GetLength(); desiredFwdSpeed *= min(1.0f, diffDir / DEG2RAD(maxDirChange)); if (!iszero(desiredFwdSpeed)) { const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f); const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis; m_forwardAction = m_fwdPID.Update(currentVel.y, desiredLocalTiltAxis.GetLength(), -1.0f, 1.0f); float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength(); Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle); if (desiredTiltAngle > 0.0001f) { const Vec3 desiredWorldTiltAxis2 = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe(); const Vec3 desiredLocalTiltAxis2 = worldMat.GetTransposed() * desiredWorldTiltAxis2; Vec3 vVelLocal = worldMat.GetTransposed() * desiredVel; vVelLocal.NormalizeSafe(); float dotup = vVelLocal.Dot(Vec3( 0.0f, 0.0f, 1.0f ) ); float currentSpeed = currentVel.GetLength(); desiredPitch = dotup * currentSpeed / 100.0f; desiredRoll = desiredTiltAngle * desiredLocalTiltAxis2.y * currentSpeed / 30.0f; } } } else { float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength(); Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle); if (desiredTiltAngle > 0.0001f) { const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe(); const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis; desiredPitch = desiredTiltAngle * desiredLocalTiltAxis.x; desiredRoll = desiredTiltAngle * desiredLocalTiltAxis.y; } } float currentHeight = m_PhysPos.pos.z; if ( m_aiRequest.HasMoveTarget() ) { m_hoveringPower = m_powerPID.Update(currentVel.z, desiredVel.z, -1.0f, 4.0f); //m_hoveringPower = (m_desiredHeight - currentHeight) * m_powerInputConst; //m_hoveringPower += m_powerInputDamping * (currentHeight - m_lastHeight) / deltaTime; if (isHorizontal) { if (desiredMoveDir.z > 0.6f || desiredMoveDir.z < -0.85f) { desiredPitch = max(-0.5f, min(0.5f, desiredMoveDir.z)) * DEG2RAD(35.0f); m_forwardAction += abs(desiredMoveDir.z); } m_liftAction = min(2.0f, max(m_liftAction, m_hoveringPower * 2.0f)); } else { m_liftAction = 0.0f; } } else { // to keep hovering at the same place m_hoveringPower = m_powerPID.Update(currentVel.z, m_desiredHeight - currentHeight, -1.0f, 1.0f); m_liftAction = 0.0f; if (m_pVehicle->GetAltitude() > 10.0f) //TODO: this line is not MTSafe { m_liftAction = m_forwardAction; } } m_actionPitch += m_pitchActionPerTilt * (desiredPitch - worldAngles.x); m_actionRoll += m_pitchActionPerTilt * (desiredRoll - worldAngles.y); Limit(m_actionPitch, -1.0f, 1.0f); Limit(m_actionRoll, -1.0f, 1.0f); Limit(m_actionYaw, -1.0f, 1.0f); if (m_horizontal > 0.0001f) { m_desiredHeight = m_PhysPos.pos.z; } Limit(m_forwardAction, -1.0f, 1.0f); }
/** Returns the 2d coordinates of a point when drawn on the mini map * texture. * \param xyz Coordinates of the point to map. * \param draw_at The coordinates in pixel on the mini map of the point, * only the first two coordinates will be used. */ void QuadGraph::mapPoint2MiniMap(const Vec3 &xyz,Vec3 *draw_at) const { draw_at->setX((xyz.getX()-m_min_coord.getX())*m_scaling); draw_at->setY((xyz.getZ()-m_min_coord.getZ())*m_scaling); } // mapPoint
void OpenSteer:: SphereObstacle:: findIntersectionWithVehiclePath (const AbstractVehicle& vehicle, PathIntersection& pi) const { // This routine is based on the Paul Bourke's derivation in: // Intersection of a Line and a Sphere (or circle) // http://www.swin.edu.au/astronomy/pbourke/geometry/sphereline/ // But the computation is done in the vehicle's local space, so // the line in question is the Z (Forward) axis of the space which // simplifies some of the calculations. float b, c, d, p, q, s; Vec3 lc; // initialize pathIntersection object to "no intersection found" pi.intersect = false; // find sphere's "local center" (lc) in the vehicle's coordinate space lc = vehicle.localizePosition (center); pi.vehicleOutside = lc.length () > radius; // if obstacle is seen from inside, but vehicle is outside, must avoid // (noticed once a vehicle got outside it ignored the obstacle 2008-5-20) if (pi.vehicleOutside && (seenFrom () == inside)) { pi.intersect = true; pi.distance = 0.0f; pi.steerHint = (center - vehicle.position()).normalize(); return; } // compute line-sphere intersection parameters const float r = radius + vehicle.radius(); b = -2 * lc.z; c = square (lc.x) + square (lc.y) + square (lc.z) - square (r); d = (b * b) - (4 * c); // when the path does not intersect the sphere if (d < 0) return; // otherwise, the path intersects the sphere in two points with // parametric coordinates of "p" and "q". (If "d" is zero the two // points are coincident, the path is tangent) s = sqrtXXX (d); p = (-b + s) / 2; q = (-b - s) / 2; // both intersections are behind us, so no potential collisions if ((p < 0) && (q < 0)) return; // at least one intersection is in front, so intersects our forward // path pi.intersect = true; pi.obstacle = this; pi.distance = ((p > 0) && (q > 0)) ? // both intersections are in front of us, find nearest one ((p < q) ? p : q) : // otherwise one is ahead and one is behind: we are INSIDE obstacle (seenFrom () == outside ? // inside a solid obstacle, so distance to obstacle is zero 0.0f : // hollow obstacle (or "both"), pick point that is in front ((p > 0) ? p : q)); pi.surfacePoint = vehicle.position() + (vehicle.forward() * pi.distance); pi.surfaceNormal = (pi.surfacePoint-center).normalize(); switch (seenFrom ()) { case outside: pi.steerHint = pi.surfaceNormal; break; case inside: pi.steerHint = -pi.surfaceNormal; break; case both: pi.steerHint = pi.surfaceNormal * (pi.vehicleOutside ? 1.0f : -1.0f); break; } }
/** Takes a snapshot of the driveline quads so they can be used as minimap. */ void QuadGraph::makeMiniMap(const core::dimension2du &dimension, const std::string &name, const video::SColor &fill_color, video::ITexture** oldRttMinimap, FrameBuffer** newRttMinimap) { const SColor oldClearColor = World::getWorld()->getClearColor(); World::getWorld()->setClearbackBufferColor(SColor(0, 255, 255, 255)); World::getWorld()->forceFogDisabled(true); *oldRttMinimap = NULL; *newRttMinimap = NULL; RTT* newRttProvider = NULL; IrrDriver::RTTProvider* oldRttProvider = NULL; if (irr_driver->isGLSL()) { newRttProvider = new RTT(dimension.Width, dimension.Height); } else { oldRttProvider = new IrrDriver::RTTProvider(dimension, name, true); } irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 255, 255, 255)); video::SColor red(128, 255, 0, 0); createMesh(/*show_invisible part of the track*/ false, /*enable_transparency*/ false, /*track_color*/ &fill_color, /*lap line color*/ &red ); m_node = irr_driver->addMesh(m_mesh); #ifdef DEBUG m_node->setName("minimap-mesh"); #endif m_node->setAutomaticCulling(0); m_node->setMaterialFlag(video::EMF_LIGHTING, false); // Add the camera: // --------------- scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode(); Vec3 bb_min, bb_max; QuadSet::get()->getBoundingBox(&bb_min, &bb_max); Vec3 center = (bb_max+bb_min)*0.5f; float dx = bb_max.getX()-bb_min.getX(); float dz = bb_max.getZ()-bb_min.getZ(); // Set the scaling correctly. Also the center point (which is used // as the camera position) needs to be adjusted: the track must // be aligned to the left/top of the texture which is used (otherwise // mapPoint2MiniMap doesn't work), so adjust the camera position // that the track is properly aligned (view from the side): // c camera // / \ . // / \ <--- camera angle // / \ . // { [-] } <--- track flat (viewed from the side) // If [-] is the shorter side of the track, then the camera will // actually render the area in { } - which is the length of the // longer side of the track. // To align the [-] side to the left, the camera must be moved // the distance betwwen '{' and '[' to the right. This distance // is exacly (longer_side - shorter_side) / 2. // So, adjust the center point by this amount: if(dz > dx) { center.setX(center.getX() + (dz-dx)*0.5f); m_scaling = dimension.Width / dz; } else { center.setZ(center.getZ() + (dx-dz)*0.5f); m_scaling = dimension.Width / dx; } float range = (dx>dz) ? dx : dz; core::matrix4 projection; projection.buildProjectionMatrixOrthoLH(range /* width */, range /* height */, -1, bb_max.getY()-bb_min.getY()+1); camera->setProjectionMatrix(projection, true); irr_driver->suppressSkyBox(); irr_driver->clearLights(); // Adjust Y position by +1 for max, -1 for min - this helps in case that // the maximum Y coordinate is negative (otherwise the minimap is mirrored) // and avoids problems for tracks which have a flat (max Y = min Y) minimap. camera->setPosition(core::vector3df(center.getX(), bb_min.getY() + 1.0f, center.getZ())); //camera->setPosition(core::vector3df(center.getX() - 5.0f, bb_min.getY() - 1 - 5.0f, center.getZ() - 15.0f)); camera->setUpVector(core::vector3df(0, 0, 1)); camera->setTarget(core::vector3df(center.getX(),bb_min.getY()-1,center.getZ())); //camera->setAspectRatio(1.0f); camera->updateAbsolutePosition(); video::ITexture* texture = NULL; FrameBuffer* frame_buffer = NULL; if (irr_driver->isGLSL()) { frame_buffer = newRttProvider->render(camera, GUIEngine::getLatestDt()); // TODO: leak //delete newRttProvider; } else { texture = oldRttProvider->renderToTexture(); delete oldRttProvider; } cleanupDebugMesh(); irr_driver->removeCameraSceneNode(camera); m_min_coord = bb_min; if (texture == NULL && frame_buffer == NULL) { Log::error("Quad Graph", "[makeMiniMap] WARNING: RTT does not appear to work," "mini-map will not be available."); } *oldRttMinimap = texture; *newRttMinimap = frame_buffer; World::getWorld()->setClearbackBufferColor(oldClearColor); World::getWorld()->forceFogDisabled(false); } // makeMiniMap
//void testvec(Vec3& a) //{ //a.print("inside testvec Vec3&, a= "); //} void testvec(Vec3 a) { a.print("inside testvec Vec3, a= "); }
//----------------------------------------------------------------------- void PUBillboardChain::updateVertexBuffer(const Mat4 &camMat) { setupBuffers(); // The contents of the vertex buffer are correct if they are not dirty // and the camera used to build the vertex buffer is still the current // camera. if (!_vertexContentDirty) return; VertexInfo vi = {Vec3(0.0f, 0.0f, 0.0f), Vec2(0.0f, 0.0f), Vec4::ONE}; _vertices.assign(_vertices.size(), vi); //HardwareVertexBufferSharedPtr pBuffer = // _vertexData->vertexBufferBinding->getBuffer(0); //void* pBufferStart = pBuffer->lock(HardwareBuffer::HBL_DISCARD); //const Vector3& camPos = cam->getDerivedPosition(); //Vector3 eyePos = mParentNode->_getDerivedOrientation().Inverse() * // (camPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale(); Vec3 eyePos(camMat.m[12], camMat.m[13], camMat.m[14]); Vec3 chainTangent; for (ChainSegmentList::iterator segi = _chainSegmentList.begin(); segi != _chainSegmentList.end(); ++segi) { ChainSegment& seg = *segi; // Skip 0 or 1 element segment counts if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) { size_t laste = seg.head; for (size_t e = seg.head; ; ++e) // until break { // Wrap forwards if (e == _maxElementsPerChain) e = 0; Element& elem = _chainElementList[e + seg.start]; CCASSERT (((e + seg.start) * 2) < 65536, "Too many elements!"); unsigned short vertexIndex = static_cast<unsigned short>((e + seg.start) * 2); //// Determine base pointer to vertex #1 //void* pBase = static_cast<void*>( // static_cast<char*>(pBufferStart) + // pBuffer->getVertexSize() * baseIdx); // Get index of next item size_t nexte = e + 1; if (nexte == _maxElementsPerChain) nexte = 0; if (e == seg.head) { // No laste, use next item chainTangent = _chainElementList[nexte + seg.start].position - elem.position; } else if (e == seg.tail) { // No nexte, use only last item chainTangent = elem.position - _chainElementList[laste + seg.start].position; } else { // A mid position, use tangent across both prev and next chainTangent = _chainElementList[nexte + seg.start].position - _chainElementList[laste + seg.start].position; } Vec3 vP1ToEye; //if( _faceCamera ) vP1ToEye = eyePos - elem.position; //else // vP1ToEye = elem.orientation * _normalBase; Vec3 vPerpendicular; Vec3::cross(chainTangent, vP1ToEye, &vPerpendicular); vPerpendicular.normalize(); vPerpendicular *= (elem.width * 0.5f); Vec3 pos0 = elem.position - vPerpendicular; Vec3 pos1 = elem.position + vPerpendicular; //float* pFloat = static_cast<float*>(pBase); //// pos1 //*pFloat++ = pos0.x; //*pFloat++ = pos0.y; //*pFloat++ = pos0.z; _vertices[vertexIndex + 0].position = pos0; //pBase = static_cast<void*>(pFloat); if (_useVertexColour) { //RGBA* pCol = static_cast<RGBA*>(pBase); //Root::getSingleton().convertColourValue(elem.colour, pCol); //pCol++; //pBase = static_cast<void*>(pCol); _vertices[vertexIndex + 0].color = elem.color; } if (_useTexCoords) { //pFloat = static_cast<float*>(pBase); if (_texCoordDir == TCD_U) { //*pFloat++ = elem.texCoord; //*pFloat++ = _otherTexCoordRange[0]; _vertices[vertexIndex + 0].uv.x = elem.texCoord; _vertices[vertexIndex + 0].uv.y = _otherTexCoordRange[0]; } else { //*pFloat++ = _otherTexCoordRange[0]; //*pFloat++ = elem.texCoord; _vertices[vertexIndex + 0].uv.x = _otherTexCoordRange[0]; _vertices[vertexIndex + 0].uv.y = elem.texCoord; } //pBase = static_cast<void*>(pFloat); } // pos2 //pFloat = static_cast<float*>(pBase); //*pFloat++ = pos1.x; //*pFloat++ = pos1.y; //*pFloat++ = pos1.z; //pBase = static_cast<void*>(pFloat); _vertices[vertexIndex + 1].position = pos1; if (_useVertexColour) { //RGBA* pCol = static_cast<RGBA*>(pBase); //Root::getSingleton().convertColourValue(elem.colour, pCol); //pCol++; //pBase = static_cast<void*>(pCol); _vertices[vertexIndex + 1].color = elem.color; } if (_useTexCoords) { //pFloat = static_cast<float*>(pBase); if (_texCoordDir == TCD_U) { //*pFloat++ = elem.texCoord; //*pFloat++ = _otherTexCoordRange[1]; _vertices[vertexIndex + 1].uv.x = elem.texCoord; _vertices[vertexIndex + 1].uv.y = _otherTexCoordRange[1]; } else { //*pFloat++ = _otherTexCoordRange[1]; //*pFloat++ = elem.texCoord; _vertices[vertexIndex + 1].uv.x = _otherTexCoordRange[1]; _vertices[vertexIndex + 1].uv.y = elem.texCoord; } } if (e == seg.tail) break; // last one laste = e; //vertexIndex += 2; } // element } // segment valid? } // each segment _vertexBuffer->updateVertices(&_vertices[0], (int)_vertices.size(), 0);; //pBuffer->unlock(); //_vertexCameraUsed = cam; _vertexContentDirty = false; }
Vec3::Vec3(Vec3& vec) { this->vec[0] = vec.x(); this->vec[1] = vec.y(); this->vec[2] = vec.z(); }
bool TMMesh::Normalize() { size_t nV = m_vertices.GetSize(); if (nV == 0) { return false; } m_barycenter = m_vertices.GetHead()->GetData().m_pos; Vec3<Real> min = m_barycenter; Vec3<Real> max = m_barycenter; Real x, y, z; for(size_t v = 1; v < nV; v++) { m_barycenter += m_vertices.GetHead()->GetData().m_pos; x = m_vertices.GetHead()->GetData().m_pos.X(); y = m_vertices.GetHead()->GetData().m_pos.Y(); z = m_vertices.GetHead()->GetData().m_pos.Z(); if ( x < min.X()) min.X() = x; else if ( x > max.X()) max.X() = x; if ( y < min.Y()) min.Y() = y; else if ( y > max.Y()) max.Y() = y; if ( z < min.Z()) min.Z() = z; else if ( z > max.Z()) max.Z() = z; m_vertices.Next(); } m_barycenter /= static_cast<Real>(nV); m_diag = static_cast<Real>(0.001 * (max-min).GetNorm()); const Real invDiag = static_cast<Real>(1.0 / m_diag); if (m_diag != 0.0) { for(size_t v = 0; v < nV; v++) { m_vertices.GetHead()->GetData().m_pos = (m_vertices.GetHead()->GetData().m_pos - m_barycenter) * invDiag; m_vertices.Next(); } } return true; }
virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo ) { switch (event) { case eFE_Initialize: break; case eFE_Activate: if (IsPortActive(pActInfo, EIP_Trigger)) { const Vec3& dir = GetPortVec3(pActInfo, EIP_LimitDir); const bool localSpace = GetPortBool(pActInfo, EIP_LocalSpace); const float rangeH = GetPortFloat(pActInfo, EIP_LimitYaw); const float rangeV = GetPortFloat(pActInfo, EIP_LimitPitch); CActor *pPlayerActor = static_cast<CActor *>(gEnv->pGame->GetIGameFramework()->GetClientActor()); if (pPlayerActor) { CPlayer::SStagingParams stagingParams; CPlayer* pPlayer = static_cast<CPlayer*> (pPlayerActor); if (dir.len2()>0.01f) { if (localSpace) { const Quat& viewQuat = pPlayer->GetViewQuatFinal(); // WC Vec3 dirWC = viewQuat * dir; stagingParams.vLimitDir = dirWC.GetNormalizedSafe(ZERO); } else stagingParams.vLimitDir = dir.GetNormalizedSafe(ZERO); } stagingParams.vLimitRangeH = DEG2RAD(rangeH); stagingParams.vLimitRangeV = DEG2RAD(rangeV); stagingParams.bLocked = GetPortBool(pActInfo, EIP_Lock); int stance = GetPortInt(pActInfo, EIP_Stance); if (stance < STANCE_NULL || stance >= STANCE_LAST) { stance = STANCE_NULL; GameWarning("[flow] PlayerStaging: stance=%d invalid", stance); } stagingParams.stance = (EStance) stance; bool bActive = (stagingParams.bLocked || (!stagingParams.vLimitDir.IsZero() && !iszero(stagingParams.vLimitRangeH) && !iszero(stagingParams.vLimitRangeV)) ); pPlayer->StagePlayer(bActive, &stagingParams); /* SActorParams* pActorParams = pPlayerActor->GetActorParams(); if (pActorParams) { CPlayer* pPlayer = static_cast<CPlayer*> (pPlayerActor); if (dir.len2()>0.01f) { if (localSpace) { const Quat& viewQuat = pPlayer->GetViewQuatFinal(); // WC Vec3 dirWC = viewQuat * dir; pActorParams->vLimitDir = dirWC.GetNormalizedSafe(ZERO); } else pActorParams->vLimitDir = dir.GetNormalizedSafe(ZERO); } else pActorParams->vLimitDir.zero(); pActorParams->vLimitRangeH = DEG2RAD(rangeH); pActorParams->vLimitRangeV = DEG2RAD(rangeV); const bool bLock = GetPortBool(pActInfo, EIP_Lock); // AlexL 23/01/2007: disable this until we have a working solution to lock player movement (action filter) // SPlayerStats* pActorStats = static_cast<SPlayerStats*> (pPlayer->GetActorStats()); // if (pActorStats) // pActorStats->spectatorMode = bLock ? CActor::eASM_Cutscene : 0; IActionMapManager* pAmMgr = g_pGame->GetIGameFramework()->GetIActionMapManager(); if (pAmMgr) pAmMgr->EnableFilter("no_move", bLock); if (bLock) { // CPlayerMovementController* pMC = static_cast<CPlayerMovementController*> (pPlayer->GetMovementController()); // pMC->Reset(); if(pPlayer->GetPlayerInput()) pPlayer->GetPlayerInput()->Reset(); } } */ } ActivateOutput(pActInfo, EOP_Done, false); } break; } }
MineEffect::MineEffect(EyeCandy* _base, bool* _dead, Vec3* _pos, const MineType _type, const Uint16 _LOD) { if (EC_DEBUG) std::cout << "MineEffect (" << this << ") created (" << type << ")." << std::endl; base = _base; dead = _dead; pos = _pos; effect_center = *pos; type = _type; LOD = base->last_forced_LOD; desired_LOD = _LOD; spawner = NULL; bounds = NULL; mover = NULL; spawner2 = NULL; mover2 = NULL; switch (type) { case DETONATE_MAGIC_IMMUNITY_REMOVAL: { spawner = new FilledSphereSpawner(0.1); mover = new ParticleMover(this); while ((int)particles.size() < LOD * 150) { const Vec3 coords = spawner->get_new_coords() + effect_center; Vec3 velocity; velocity.randomize(0.5); velocity.y = 0.2; Particle * p = #ifdef NEW_TEXTURES new MineParticle(this, mover, coords, velocity, 0.2, 1.0, 3.0, 3.0, 3.0, EC_SIMPLE, LOD, type); #else /* NEW_TEXTURES */ new MineParticle(this, mover, coords, velocity, 0.2, 1.0, 3.0, 3.0, 3.0, &(base->TexSimple), LOD, type); #endif /* NEW_TEXTURES */ if (!base->push_back_particle(p)) break; } break; } case DETONATE_UNINVIZIBILIZER: { effect_center.y += 1.8; spawner = new HollowDiscSpawner(0.3); mover = new ParticleMover(this); while ((int)particles.size() < LOD * 200) { Vec3 coords = spawner->get_new_coords(); Vec3 velocity; velocity.randomize(); velocity.normalize(0.2); coords += effect_center; coords.y = randfloat(1.8); Particle * p = #ifdef NEW_TEXTURES new MineParticle(this, mover, coords, velocity, 1.2, 1.0, 3.0, 3.0, 3.0, EC_SIMPLE, LOD, type); #else /* NEW_TEXTURES */ new MineParticle(this, mover, coords, velocity, 1.2, 1.0, 3.0, 3.0, 3.0, &(base->TexSimple), LOD, type); #endif /* NEW_TEXTURES */ if (!base->push_back_particle(p)) break; } break; } case DETONATE_MANA_DRAINER: { effect_center.y += 1.6; spawner = new HollowDiscSpawner(0.3); mover = new SimpleGravityMover(this); while ((int)particles.size() < LOD * 50) { const Vec3 coords = spawner->get_new_coords() + effect_center; Vec3 velocity; velocity.randomize(); velocity.normalize(0.2); Particle * p = #ifdef NEW_TEXTURES new MineParticle(this, mover, coords, velocity, 0.3, 1.0, 0.8, 0.35, 0.7, EC_SIMPLE, LOD, type); #else /* NEW_TEXTURES */ new MineParticle(this, mover, coords, velocity, 0.3, 1.0, 0.8, 0.35, 0.7, &(base->TexSimple), LOD, type); #endif /* NEW_TEXTURES */ if (!base->push_back_particle(p)) break; } break; } case DETONATE_MANA_BURNER: { effect_center.y += 1.0; spawner = new FilledSphereSpawner(0.5); mover = new GravityMover(this, &effect_center, 8e9); while ((int)particles.size() < LOD * 100) { const Vec3 coords = spawner->get_new_coords() + effect_center; Vec3 velocity; velocity.randomize(); velocity.normalize(0.9); Particle * p = #ifdef NEW_TEXTURES new MineParticle(this, mover, coords, velocity, 0.5, 0.5, 0.8, 0.35, 0.7, EC_TWINFLARE, LOD, type); #else /* NEW_TEXTURES */ new MineParticle(this, mover, coords, velocity, 0.5, 0.5, 0.8, 0.35, 0.7, &(base->TexTwinflare), LOD, type); #endif /* NEW_TEXTURES */ if (!base->push_back_particle(p)) break; } break; } case DETONATE_CALTROP: case DETONATE_CALTROP_POISON: { effect_center.y += 0.05; mover = new SimpleGravityMover(this); spawner = new HollowSphereSpawner(0.1); for (int i = 0; i < LOD * 10; i++) { const Vec3 coords = spawner->get_new_coords() + effect_center; const Vec3 velocity(0.0, 5.0, 0.0); #ifdef NEW_TEXTURES Particle* p = new MineParticle(this, mover, coords, velocity, 0.75, 0.6, 0.4, (type == DETONATE_CALTROP ? 0.3 : 0.5), 0.3, EC_TWINFLARE, LOD, type); #else /* NEW_TEXTURES */ Particle* p = new MineParticle(this, mover, coords, velocity, 0.75, 0.6, 0.4, (type == DETONATE_CALTROP ? 0.3 : 0.5), 0.3, &(base->TexTwinflare), LOD, type); #endif /* NEW_TEXTURES */ p->state = 1; if (!base->push_back_particle(p)) break; } break; } case DETONATE_TRAP: { effect_center.y += 1.25; mover = new OrbitalMover(this, effect_center); spawner = new HollowSphereSpawner(1.25); Particle* p; for (int i = 0; i < LOD * 100; i++) { Vec3 c = effect_center; c.y = -0.3 + (i * 0.05); Vec3 vel; vel.randomize(); vel.normalize(2.0); vel *= randfloat() * 4.0; #ifdef NEW_TEXTURES p = new MineParticle(this, mover, c, vel, 0.2, 1.0, 1.0, 1.0, 1.0, EC_VOID, LOD, type); #else /* NEW_TEXTURES */ p = new MineParticle(this, mover, c, vel, 0.2, 1.0, 1.0, 1.0, 1.0, &(base->TexVoid), LOD, type); #endif /* NEW_TEXTURES */ if (!base->push_back_particle(p)) break; dynamic_cast<OrbitalMover*>(mover)->setParticleData(p, OrbitalParticleData(i, 10, 0.45, 10) ); } break; } case DETONATE_TYPE1_SMALL: case DETONATE_TYPE1_MEDIUM: case DETONATE_TYPE1_LARGE: { spawner = new FilledSphereSpawner(0.1); mover = new ParticleMover(this); const float scale = (type == DETONATE_TYPE1_SMALL ? 0.75 : type == DETONATE_TYPE1_MEDIUM ? 1.25 : 2.0); Vec3 wind; wind.randomize(); wind.normalize(0.25); wind.y = 0; for (int i = 0; i < LOD * 100 * scale; i++) { Vec3 coords = spawner->get_new_coords(); Vec3 velocity = coords * 10.0 * sqrt(scale); velocity.y = fabs(velocity.y) * 3.0f; coords += effect_center; coords.y -= 0.1; #ifdef NEW_TEXTURES Particle * p = new MineParticleFire(this, mover, coords, velocity, 0.5, 1.0, 1.0, randcolor(0.75), 0.0, EC_FLARE, LOD); #else /* NEW_TEXTURES */ Particle * p = new MineParticleFire(this, mover, coords, velocity, 0.5, 1.0, 1.0, randcolor(0.75), 0.0, &(base->TexFlare), LOD); #endif /* NEW_TEXTURES */ if (!base->push_back_particle(p)) break; } spawner = new FilledSphereSpawner(0.5 * std::sqrt(scale)); for (int i = 0; i < LOD * 32 * scale; i++) { Vec3 coords = spawner->get_new_coords(); Vec3 velocity; coords += effect_center; float grey = randcolor(0.5); velocity.randomize(); velocity.normalize(0.25 * scale); velocity.y = fabs(velocity.y) * 6.0f; velocity += wind; #ifdef NEW_TEXTURES Particle *p = new MineParticleSmoke(this, mover, coords, velocity, 3.0 + randcoord(3.0 * scale), 0.0, grey, grey, grey, EC_SIMPLE, LOD); #else /* NEW_TEXTURES */ Particle *p = new MineParticleSmoke(this, mover, coords, velocity, 3.0 + randcoord(3.0 * scale), 0.0, grey, grey, grey, &(base->TexSimple), LOD); #endif /* NEW_TEXTURES */ if (!base->push_back_particle(p)) break; } break; } } }
bool CCameraTracking::IdentifyObstacle(const Vec3 &vCamDir, const CPlayer &hero) { //check player direction Vec3 newDir = -hero.GetEntity()->GetForwardDir(); newDir.z += vCamDir.z; newDir.normalize(); //compute rotation speed const float fHeroSpeedModifier = clamp(hero.GetActorStats()->speedFlat / 4.0f, 0.3f, 1.0f); const float fNewSpeed = g_pGameCVars->cl_cam_tracking_rotation_speed * m_fFrameTime * fHeroSpeedModifier; m_fSpeed = InterpolateTo(m_fSpeed, fNewSpeed, (fNewSpeed>m_fSpeed)?0.1f:0.3f); //m_fSpeed = (g_fInterpolationRate * m_fSpeed + speed) * g_fInterpolationWeight; //get ray data from camera ray tests ray_hit *pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_RIGHT); if(!pRayHit || pRayHit->dist == 0.0f) pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_RIGHT); bool bHitsRight = (pRayHit && pRayHit->dist > 0.0f); Vec3 dirRight = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_RIGHT)):Vec3(ZERO); //ray data left side pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_LEFT); if(!pRayHit || pRayHit->dist == 0.0f) pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_LEFT); bool bHitsLeft = (pRayHit && pRayHit->dist > 0.0f); Vec3 dirLeft = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_LEFT)):Vec3(ZERO); //left or right if(bHitsRight ^ bHitsLeft) { //find rotation direction if(!bHitsRight && !bHitsLeft) { if(m_eLastDirYaw == eTD_LEFT) //continue last direction newDir = dirLeft; else newDir = dirRight; } else if(!bHitsRight) { m_eLastDirYaw = eTD_RIGHT; newDir = dirRight; } else { m_eLastDirYaw = eTD_LEFT; newDir = dirLeft; } //compute yaw/pitch for target position float newYaw = 0.0f; float newPitch = 0.0f; float newDist = 0.0f; CartesianToSpherical(newDir * m_curCamOrientation.m_fDist, newYaw, newPitch, newDist); newYaw += gf_PI; //now interpolate to target //compute delta yaw m_fYawDelta = (newYaw - m_curCamOrientation.m_fYaw) * m_fSpeed; if(m_eLastDirYaw == eTD_RIGHT && m_fYawDelta < 0.0f || m_eLastDirYaw == eTD_LEFT && m_fYawDelta > 0.0f) m_fYawDelta *= -1.0f; } //compute top/bottom rotation //ray data top side pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_CENTER); bool bHitsTop = (pRayHit && pRayHit->dist > 0.0f)?true:false; Vec3 vDirTop = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_CENTER)):Vec3(ZERO); //ray data bottom side pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_CENTER); bool bHitsBottom = (pRayHit && pRayHit->dist > 0.0f)?true:false; Vec3 vDirBottom = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_BOTTOM_CENTER)):Vec3(ZERO); //top or bottom (if not left or right) if(g_pGameCVars->cl_cam_tracking_allow_pitch && (bHitsTop ^ bHitsBottom) && !(bHitsRight ^ bHitsLeft)) { //find rotation direction if(!bHitsTop && !bHitsBottom) { if(m_eLastDirPitch == eTD_TOP) //continue last direction newDir = vDirTop; else newDir = vDirBottom; } else if(!bHitsBottom) { m_eLastDirPitch = eTD_BOTTOM; newDir = vDirBottom; } else { m_eLastDirPitch = eTD_TOP; newDir = vDirTop; } //compute yaw/pitch for target position float newYaw = 0.0f; float newPitch = 0.0f; float newDist = 0.0f; //newdist (raydist) will be ignored CartesianToSpherical(newDir, newYaw, newPitch, newDist); //compute delta pitch m_fPitchDelta = (newPitch - m_curCamOrientation.m_fPitch) * m_fSpeed * 10.0f; } //if all rays hit - don't bother! //this is a termination condition when the camera is pulled through geometry if(bHitsLeft & bHitsRight & bHitsBottom & bHitsTop) { if(m_bViewCovered) { //if obstacle behind player //if(g_rHit.dist > 0.0f) //this is a strange fix, but it's working better and is much cheaper than a raycast if(fabsf(m_fYawDelta) < 0.01f && fabsf(m_fPitchDelta) > 0.001f) return false; } m_bViewCovered = true; } else m_bViewCovered = false; return true; }