void CVehicleWeaponControlled::Update(SEntityUpdateContext& ctx, int update) { IVehicle *pVehicle = m_vehicleId ? gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(m_vehicleId) : NULL; if (!m_vehicleId && GetEntity()->GetParent()) { IEntity *entity = GetEntity(); if (entity) { IEntity *parent = entity->GetParent(); if (parent) { m_vehicleId = parent->GetId(); pVehicle = gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(parent->GetId()); } } } if (pVehicle) { IVehiclePart *pPart = pVehicle->GetWeaponParentPart(GetEntityId()); if(pPart) { if(IVehiclePart *pParentPart = pPart->GetParent()) { CRY_ASSERT(pVehicle->GetEntity()); if(ICharacterInstance *characterInst = pVehicle->GetEntity()->GetCharacter(pParentPart->GetSlot())) { if(ISkeletonPose* pose = characterInst->GetISkeletonPose()) { IDefaultSkeleton& rIDefaultSkeleton = characterInst->GetIDefaultSkeleton(); int16 joint = rIDefaultSkeleton.GetJointIDByName(pPart->GetName()); const QuatT &jQuat = pose->GetAbsJointByID(joint); Matrix34 localT(jQuat); localT.SetTranslation(jQuat.t/* - Vec3(0.0f, 0.75f, 0.0f)*/); Matrix34 vehicleWorldTm = pVehicle->GetEntity()->GetWorldTM(); Matrix34 mat = vehicleWorldTm * localT; Vec3 vehicleSide2 = pPart->GetParent()->GetLocalTM(true, true).GetTranslation(); CPlayer *pl = this->GetOwnerPlayer(); Matrix33 mat2; if (!m_destination.IsEquivalent(ZERO)) { Vec3 diff = GetDestination() - mat.GetTranslation(); //pPart->GetWorldTM().GetTranslation(); diff.Normalize(); Matrix33 loc(mat); loc.Invert(); Vec3 diffLocal = loc.TransformVector(diff); Matrix33 desMat; desMat.SetRotationVDir(diffLocal, 0.0f); Vec3 test = GetEntity()->GetLocalTM().GetColumn0(); Ang3 testTM(desMat); float za = testTM.x - m_Angles.x; za = (za < 0.0f) ? -gf_PI : gf_PI; za *= 0.05f * ctx.fFrameTime; m_Angles.x += za; Limit(m_Angles.x, -gf_PI * 0.33f, gf_PI * 0.33f); if (testTM.z > m_Angles.z + 0.05f) { m_Angles.z += gf_PI * factor1 * ctx.fFrameTime; } else if (testTM.z < m_Angles.z - 0.05f) { m_Angles.z -= gf_PI * factor1 * ctx.fFrameTime; } else { m_Angles.z = testTM.z; } Limit(m_Angles.z, -gf_PI * 0.33f, gf_PI * 0.33f); mat2.SetRotationXYZ(m_Angles); } else { if (!m_FireBlocked) { m_Angles.x = m_Angles.x - ctx.fFrameTime * factor2 * m_Angles.x; m_Angles.z = m_Angles.z - ctx.fFrameTime * factor2 * m_Angles.z; } mat2.SetRotationXYZ(m_Angles); } mat = mat * mat2; GetEntity()->SetWorldTM(mat); if (pl) { Matrix34 worldGunMat = vehicleWorldTm * localT; if (!pl->IsDead()) { Vec3 trans = worldGunMat.GetTranslation() - worldGunMat.GetColumn2() * 0.7f; worldGunMat.SetTranslation(trans); pl->GetEntity()->SetWorldTM(worldGunMat); float dot = mat.GetColumn1().dot(worldGunMat.GetColumn0()); Update3PAnim(pl, 0.5f - dot * 0.5f, ctx.fFrameTime, mat); } else { ICharacterInstance* pCharacter = pl->GetEntity()->GetCharacter(0); int boneId = pCharacter ? pCharacter->GetIDefaultSkeleton().GetJointIDByName("Spine03") : 7; pl->LinkToMountedWeapon(0); if (IVehicleSeat* seat = pVehicle->GetSeatForPassenger(pl->GetEntityId())) { seat->Exit(false, true); } Matrix33 rot(worldGunMat); Vec3 offset(0.0f, 0.0f, 0.70f); Vec3 transformedOff = rot.TransformVector(offset); Vec3 trans = worldGunMat.GetTranslation(); trans -= transformedOff; worldGunMat.SetTranslation(trans); pl->GetEntity()->SetWorldTM(worldGunMat); pl->GetEntity()->SetPos(worldGunMat.GetTranslation()); //worldGunMat.GetTranslation()); pl->RagDollize(true); if (boneId > -1) { IPhysicalEntity *physEnt = pl->GetEntity()->GetPhysics(); if (physEnt) { pe_simulation_params simulationParams; physEnt->GetParams(&simulationParams); pe_params_pos pos; pos.pos = GetEntity()->GetPos(); physEnt->SetParams(&pos); pe_action_impulse impulse; impulse.ipart = boneId; impulse.angImpulse = Vec3(0.0f, 0.0f, 1.0f); impulse.impulse = worldGunMat.GetColumn1() * -1.5f * simulationParams.mass; physEnt->Action(&impulse); } } StopUse(GetOwnerId()); SetOwnerId(0); StopFire(); m_FireBlocked = true; } // IsDead } // pl } // pose } // characterInst } // pParentPart } // pPart } // pVehicle Base::Update(ctx, update); RequireUpdate(eIUS_General); }
void Set(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t) { Limit(v, owner, id, tabIndex, t); }
void Scaler::Dither(int32 fromRow, int32 toRow) { BBitmap* src; BBitmap* dest; intType destW; intType x, y; uchar* srcBits; intType srcBPR; uchar* srcDataRow; uchar* srcData; uchar* destBits; intType destBPR; uchar* destDataRow; uchar* destData; const int32 kBPP = 4; DitheringColumnData* columnData0; DitheringColumnData* columnData; DitheringColumnData* cd; BScreen screen; intType error[3], err[3]; src = fScaledImage; dest = GetDestImage(); ASSERT(src->ColorSpace() == B_RGB32 || src->ColorSpace() == B_RGBA32); ASSERT(dest->ColorSpace() == B_CMAP8); ASSERT(src->Bounds().IntegerWidth() == dest->Bounds().IntegerWidth()); ASSERT(src->Bounds().IntegerHeight() == dest->Bounds().IntegerHeight()); destW = dest->Bounds().IntegerWidth(); srcBits = (uchar*)src->Bits(); srcBPR = src->BytesPerRow(); destBits = (uchar*)dest->Bits(); destBPR = dest->BytesPerRow(); // Allocate space for sentinel at left and right bounds, // so that columnData[-1] and columnData[destW+1] can be safely accessed columnData0 = new DitheringColumnData[destW+3]; columnData = columnData0 + 1; // clear error cd = columnData; for (x = destW; x >= 0; x --, cd ++) { cd->error[0] = cd->error[1] = cd->error[2] =0; } srcDataRow = srcBits + fromRow * srcBPR; destDataRow = destBits + fromRow * destBPR; for (y = fromRow; IsRunning() && y <= toRow; y ++, srcDataRow += srcBPR, destDataRow += destBPR) { // left to right error[0] = error[1] = error[2] = 0; srcData = srcDataRow; destData = destDataRow; for (x = 0; x <= destW; x ++, srcData += kBPP, destData += 1) { rgb_color color, actualColor; uint8 index; color.red = Limit(srcData[2] + error[0] / 16); color.green = Limit(srcData[1] + error[1] / 16); color.blue = Limit(srcData[0] + error[2] / 16); index = screen.IndexForColor(color); actualColor = screen.ColorForIndex(index); *destData = index; err[0] = color.red - actualColor.red; err[1] = color.green -actualColor.green; err[2] = color.blue -actualColor.blue; // distribute error // get error for next pixel cd = &columnData[x+1]; error[0] = cd->error[0] + 7 * err[0]; error[1] = cd->error[1] + 7 * err[1]; error[2] = cd->error[2] + 7 * err[2]; // set error for right pixel below current pixel cd->error[0] = err[0]; cd->error[1] = err[1]; cd->error[2] = err[2]; // add error for pixel below current pixel cd --; cd->error[0] += 5 * err[0]; cd->error[1] += 5 * err[1]; cd->error[2] += 5 * err[2]; // add error for left pixel below current pixel cd --; cd->error[0] += 3 * err[0]; cd->error[1] += 3 * err[1]; cd->error[2] += 3 * err[2]; } // Note: Alogrithm has good results with "left to right" already // Optionally remove code to end of block: y ++; srcDataRow += srcBPR; destDataRow += destBPR; if (y > toRow) break; // right to left error[0] = error[1] = error[2] = 0; srcData = srcDataRow + destW * kBPP; destData = destDataRow + destW; for (x = 0; x <= destW; x ++, srcData -= kBPP, destData -= 1) { rgb_color color, actualColor; uint8 index; color.red = Limit(srcData[2] + error[0] / 16); color.green = Limit(srcData[1] + error[1] / 16); color.blue = Limit(srcData[0] + error[2] / 16); index = screen.IndexForColor(color); actualColor = screen.ColorForIndex(index); *destData = index; err[0] = color.red - actualColor.red; err[1] = color.green -actualColor.green; err[2] = color.blue -actualColor.blue; // distribute error // get error for next pixel cd = &columnData[x-1]; error[0] = cd->error[0] + 7 * err[0]; error[1] = cd->error[1] + 7 * err[1]; error[2] = cd->error[2] + 7 * err[2]; // set error for left pixel below current pixel cd->error[0] = err[0]; cd->error[1] = err[1]; cd->error[2] = err[2]; // add error for pixel below current pixel cd ++; cd->error[0] += 5 * err[0]; cd->error[1] += 5 * err[1]; cd->error[2] += 5 * err[2]; // add error for right pixel below current pixel cd ++; cd->error[0] += 3 * err[0]; cd->error[1] += 3 * err[1]; cd->error[2] += 3 * err[2]; } } delete[] columnData0; }
bool EntropyDrive::DriveRobotTrig(float MoveValue, float RotateValue) { float LeftMotors = 0; float RightMotors = 0; float OutsideWheels = 0; float InsideWheels = 0; float Hypot = 0; float AbsMoveValue = 0; float AbsRotateValue = 0; float CompMoveValuePlus=0.99; float CompMoveValueMinus=0.60; float CompRotateValuePlus=0.99; float CompRotateValueMinus=0.99; //Normalize Joystick inputs if (MoveValue >= 0.0) { MoveValue=MoveValue/CompMoveValuePlus; } else { MoveValue=MoveValue/CompMoveValueMinus; } if (RotateValue>=0.0) { RotateValue=RotateValue/CompRotateValuePlus; } else { RotateValue=RotateValue/CompRotateValueMinus; } MoveValue=Limit(MoveValue); RotateValue=Limit(RotateValue); AbsMoveValue=absolutevalue(MoveValue); AbsRotateValue= absolutevalue(RotateValue); //Theta = atanf(AbsMoveValue/(AbsRotateValue+0.000001)); //Theta = asinf(0.2); Hypot = sqrt(AbsMoveValue*AbsMoveValue+AbsRotateValue*AbsRotateValue); OutsideWheels = AbsMoveValue*(AbsMoveValue/Hypot); InsideWheels = AbsMoveValue*( 1- (AbsRotateValue/Hypot)); //Scale Motor inputs if (RotateValue<=0.0) { LeftMotors = InsideWheels * MoveValue/AbsMoveValue; RightMotors = OutsideWheels * MoveValue/AbsMoveValue; } else { LeftMotors = OutsideWheels * MoveValue/AbsMoveValue; RightMotors = InsideWheels * MoveValue/AbsMoveValue; } //Command motors wpiDrive->SetLeftRightMotorOutputs( -1*LeftMotors,-1*RightMotors ); return true; }
void CPlayerRotation::GetStanceAngleLimits(float &minAngle,float &maxAngle) { EStance stance = m_player.GetStance(); switch(stance) { default: case STANCE_CROUCH: case STANCE_STAND: minAngle = -80.0f; maxAngle = 80.0f; break; case STANCE_PRONE: minAngle = -35.0f; maxAngle = 45.0f; break; } //Limit camera rotation on ladders(to prevent clipping) if(m_player.m_stats.isOnLadder) { minAngle = -40.0f; maxAngle = 80.0f; } if(m_stats.grabbedHeavyEntity!=0) { minAngle = -35.0f; //Limit angle to prevent clipping, throw objects at feet, etc... } // SNH: additional restriction based on weapon type if prone. if(m_player.GetStance() == STANCE_PRONE && g_pGameCVars->g_proneAimAngleRestrict_Enable != 0) { float dist = 0.0f; CItem *pItem = (CItem *)(m_player.GetCurrentItem()); if(pItem) dist = pItem->GetParams().raise_distance; SMovementState movestate; m_player.m_pMovementController->GetMovementState(movestate); // try a cylinder intersection test IPhysicalEntity *pIgnore[2]; pIgnore[0] = m_player.GetEntity()->GetPhysics(); pIgnore[1] = pItem ? pItem->GetEntity()->GetPhysics() : NULL; primitives::cylinder cyl; cyl.r = 0.05f; cyl.axis = movestate.aimDirection; cyl.hh = dist; cyl.center = movestate.weaponPosition + movestate.aimDirection*cyl.hh; //gEnv->pRenderer->GetIRenderAuxGeom()->DrawCylinder(cyl.center, cyl.axis, cyl.r, cyl.hh, ColorF(0.4f,1.0f,0.6f, 0.2f)); float n = 0.0f; geom_contact *contacts; intersection_params params; WriteLockCond lockContacts; params.bStopAtFirstTri = false; params.bSweepTest = false; params.bNoBorder = true; params.bNoAreaContacts = true; n = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(primitives::cylinder::type, &cyl, Vec3(0,0,2), ent_static|ent_terrain, &contacts, 0, geom_colltype_player, ¶ms, 0, 0, pIgnore, pIgnore[1]?2:1), lockContacts; int ret = (int)n; geom_contact *currentc = contacts; for(int i=0; i<ret; i++) { geom_contact *contact = currentc; if(contact && (fabs_tpl(contact->n.z)>0.2f)) { Vec3 dir = contact->pt - movestate.weaponPosition; dir.NormalizeSafe(); Vec3 horiz = dir; horiz.z = 0.0f; horiz.NormalizeSafe(); float cosangle = dir.Dot(horiz); Limit(cosangle, -1.0f, 1.0f); float newMin = acos_tpl(cosangle); newMin = -newMin * 180.0f / gf_PI; //float col[] = {1,1,1,1}; //gEnv->pRenderer->Draw2dLabel(100,100, 1.0f, col, false, "minangle: %.2f", newMin); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(contact->pt, 0.03f, ColorF(1,0,0,1)); minAngle = MAX(newMin, minAngle); } ++currentc; } } minAngle *= gf_PI/180.0f; maxAngle *= gf_PI/180.0f; }
void PID_LineCfg(uint16_t currLine, uint16_t setLine, PID_Config *config) { int32_t pid, speed, speedL, speedR; MOT_Direction directionL=MOT_DIR_FORWARD, directionR=MOT_DIR_FORWARD; pid = PID(currLine, setLine, config); uint8_t errorPercent; errorPercent = errorWithinPercent(currLine-setLine); /* change speed depending on error */ /* transform into different speed for motors. The PID is used as difference value to the motor PWM */ if (errorPercent <= 20) { /* pretty on center: move forward both motors with base speed */ speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100); /* 100% */ pid = Limit(pid, -speed, speed); if (pid<0) { /* turn right */ speedR = speed; speedL = speed-pid; } else { /* turn left */ speedR = speed+pid; speedL = speed; } } else if (errorPercent <= 40) { /* outside left/right halve position from center, slow down one motor and speed up the other */ speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100)*8/10; /* 80% */ pid = Limit(pid, -speed, speed); if (pid<0) { /* turn right */ speedR = speed+pid; /* decrease speed */ speedL = speed-pid; /* increase speed */ } else { /* turn left */ speedR = speed+pid; /* increase speed */ speedL = speed-pid; /* decrease speed */ } } else if (errorPercent <= 70) { speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100)*6/10; /* %60 */ pid = Limit(pid, -speed, speed); if (pid<0) { /* turn right */ speedR = 0 /*maxSpeed+pid*/; /* decrease speed */ speedL = speed-pid; /* increase speed */ } else { /* turn left */ speedR = speed+pid; /* increase speed */ speedL = 0 /*maxSpeed-pid*/; /* decrease speed */ } } else { /* line is far to the left or right: use backward motor motion */ speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100)*10/10; /* %80 */ if (pid<0) { /* turn right */ speedR = -speed+pid; /* decrease speed */ speedL = speed-pid; /* increase speed */ } else { /* turn left */ speedR = speed+pid; /* increase speed */ speedL = -speed-pid; /* decrease speed */ } speedL = Limit(speedL, -speed, speed); speedR = Limit(speedR, -speed, speed); directionL = AbsSpeed(&speedL); directionR = AbsSpeed(&speedR); } /* speed is now always positive, make sure it is within 16bit PWM boundary */ if (speedL>0xFFFF) { speedL = 0xFFFF; } else if (speedL<0) { speedL = 0; } if (speedR>0xFFFF) { speedR = 0xFFFF; } else if (speedR<0) { speedR = 0; } /* send new speed values to motor */ MOT_SetVal(MOT_GetMotorHandle(MOT_MOTOR_LEFT), 0xFFFF-speedL); /* PWM is low active */ MOT_SetDirection(MOT_GetMotorHandle(MOT_MOTOR_LEFT), directionL); MOT_SetVal(MOT_GetMotorHandle(MOT_MOTOR_RIGHT), 0xFFFF-speedR); /* PWM is low active */ MOT_SetDirection(MOT_GetMotorHandle(MOT_MOTOR_RIGHT), directionR); }
void FastImage::Blue(int y, int x, int v){ if( y > hauteur || y < 0 ) return; if( x > largeur || x < 0 ) return; image[4*x + line_width * y] = Limit(v); }
// Simple 2-poles resonant filter void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modifier) const //---------------------------------------------------------------------------------------- { int cutoff = (int)pChn->nCutOff + (int)pChn->nCutSwing; int resonance = (int)(pChn->nResonance & 0x7F) + (int)pChn->nResSwing; Limit(cutoff, 0, 127); Limit(resonance, 0, 127); if(!GetModFlag(MSF_OLDVOLSWING)) { pChn->nCutOff = (uint8)cutoff; pChn->nCutSwing = 0; pChn->nResonance = (uint8)resonance; pChn->nResSwing = 0; } float d, e; // flt_modifier is in [-256, 256], so cutoff is in [0, 127 * 2] after this calculation. const int computedCutoff = cutoff * (flt_modifier + 256) / 256; // Filtering is only ever done in IT if either cutoff is not full or if resonance is set. if(IsCompatibleMode(TRK_IMPULSETRACKER) && resonance == 0 && computedCutoff >= 254) { if(pChn->rowCommand.IsNote() && !pChn->dwFlags[CHN_PORTAMENTO] && !pChn->nMasterChn && m_SongFlags[SONG_FIRSTTICK]) { // Z7F next to a note disables the filter, however in other cases this should not happen. // Test cases: filter-reset.it, filter-reset-carry.it, filter-nna.it pChn->dwFlags.reset(CHN_FILTER); } return; } pChn->dwFlags.set(CHN_FILTER); if(UseITFilterMode()) { const float freqParameterMultiplier = 128.0f / (24.0f * 256.0f); // 2 ^ (i / 24 * 256) float frequency = 110.0f * pow(2.0f, 0.25f + (float)computedCutoff * freqParameterMultiplier); LimitMax(frequency, (float)(m_MixerSettings.gdwMixingFreq / 2)); const float r = (float)m_MixerSettings.gdwMixingFreq / (2.0f * (float)M_PI * frequency); d = ITResonanceTable[resonance] * r + ITResonanceTable[resonance] - 1.0f; e = r * r; } else { float fc = (float)CutOffToFrequency(cutoff, flt_modifier); const float dmpfac = pow(10.0f, -((24.0f / 128.0f) * (float)resonance) / 20.0f); fc *= (float)(2.0f * (float)M_PI / (float)m_MixerSettings.gdwMixingFreq); d = (1.0f - 2.0f * dmpfac) * fc; LimitMax(d, 2.0f); d = (2.0f * dmpfac - d) / fc; e = pow(1.0f / fc, 2.0f); } float fg = 1.0f / (1.0f + d + e); float fb0 = (d + e + e) / (1 + d + e); float fb1 = -e / (1.0f + d + e); switch(pChn->nFilterMode) { case FLTMODE_HIGHPASS: pChn->nFilter_A0 = 1.0f - fg; pChn->nFilter_B0 = fb0; pChn->nFilter_B1 = fb1; pChn->nFilter_HP = -1; break; default: pChn->nFilter_A0 = fg; pChn->nFilter_B0 = fb0; pChn->nFilter_B1 = fb1; pChn->nFilter_HP = 0; break; } if (bReset) { pChn->nFilter_Y1 = pChn->nFilter_Y2 = 0; pChn->nFilter_Y3 = pChn->nFilter_Y4 = 0; } }
//------------------------------------------------------------------------ void CVehicleSeatActionRotateTurret::UpdatePartRotation(EVehicleTurretRotationType eType, float frameTime) { CRY_ASSERT( eType < eVTRT_NumRotationTypes ); const float threshold = 0.01f; if (frameTime > 0.08f) frameTime = 0.08f; CVehiclePartBase* pPart = m_rotations[eType].m_pPart; IVehiclePart* pParent = pPart->GetParent(); IActor* pActor = m_pSeat->GetPassengerActor(); float rot_dir = fsgnf(m_rotations[eType].m_action); float max_rotation = fabsf(m_rotations[eType].m_action); float rot_speed = DEG2RAD(fabsf(m_rotations[eType].m_speed)) * GetDamageSpeedMul(pPart); float delta = rot_dir * rot_speed * frameTime; delta += m_rotations[eType].m_aimAssist; delta = fmod(delta, gf_PI2); if (delta > gf_PI) delta -= gf_PI2; if (delta < -gf_PI) delta += gf_PI2; Limit( delta, -max_rotation, max_rotation); Ang3 deltaAngles(ZERO); if (eType == eVTRT_Pitch) deltaAngles.x = delta; else if (eType == eVTRT_Yaw) deltaAngles.z = delta; else CRY_ASSERT(false && "Unknown turret rotation"); Matrix34 tm = pPart->GetLocalBaseTM(); Ang3 angles = Ang3::GetAnglesXYZ(tm) + deltaAngles; float lerp = 0.f; if (eType == eVTRT_Pitch) { Vec3 yAxis = m_rotations[eVTRT_Yaw].m_pPart->GetLocalBaseTM().GetColumn1(); yAxis.z = 0.f; yAxis.normalize(); lerp = 0.5f - 0.5f * yAxis.y; Limit(lerp, 0.0f, 1.0f); } // clamp to limits if (m_rotations[eType].m_minLimitF != 0.0f || m_rotations[eType].m_maxLimit != 0.0f) { // Different clamp angles facing forwards/backwards float minLimit = m_rotations[eType].m_minLimitF + (m_rotations[eType].m_minLimitB - m_rotations[eType].m_minLimitF) * lerp; float angle = (eType == eVTRT_Pitch) ? angles.x : angles.z; if (angle > m_rotations[eType].m_maxLimit || angle < minLimit) { angle = clamp_tpl(angle, minLimit, m_rotations[eType].m_maxLimit); m_rotations[eType].m_currentValue = 0.f; if (eType == eVTRT_Pitch) angles.x = angle; else angles.z = angle; } } m_rotations[eType].m_orientation.Set(Quat::CreateRotationXYZ(angles)); m_rotations[eType].m_orientation.Update(frameTime); m_rotations[eType].m_action = 0.0f; m_rotations[eType].m_aimAssist = 0.0f; Matrix34 newTM(m_rotations[eType].m_orientation.Get().GetNormalized()); newTM.SetTranslation(tm.GetTranslation()); pPart->SetLocalBaseTM(newTM); // store world-space rotation const Matrix34 &worldTM = pPart->GetWorldTM(); m_rotations[eType].m_prevWorldQuat = Quat(worldTM); CRY_ASSERT(m_rotations[eType].m_prevWorldQuat.IsValid()); // now update the turret sound based on the calculated rotation speed UpdateRotationSound(eType, delta, frameTime); }
//------------------------------------------------------------------------ void CIronSight::UpdateDepthOfField(CActor *pActor, float frameTime, float t) { if(pActor) { CPlayer *pPlayer = static_cast<CPlayer *>(pActor); if(IMovementController *pMV = pActor->GetMovementController()) { SMovementState ms; pMV->GetMovementState(ms); Vec3 start = ms.eyePosition; Vec3 dir = ms.eyeDirection; static ray_hit hit; IPhysicalEntity *pSkipEntities[10]; int nSkip = CSingle::GetSkipEntities(m_pWeapon, pSkipEntities, 10); // jitter the direction (non-uniform disk sampling ... we want to bias the center in this case) f32 cosTheta, sinTheta; f32 theta = Random() * gf_PI2; f32 spreadAngle = DEG2RAD(g_pGameCVars->g_dof_sampleAngle)/2.0f; f32 scale = tan_tpl(spreadAngle); f32 radiusSqrt = scale * Random(); sincos_tpl(theta, &cosTheta, &sinTheta); f32 x = radiusSqrt * cosTheta; f32 y = radiusSqrt * sinTheta; Matrix33 viewRotation(pPlayer->GetViewQuatFinal()); Vec3 xOff = x * viewRotation.GetColumn0(); Vec3 yOff = y * viewRotation.GetColumn2(); // jitter if(true) { dir += xOff + yOff; dir.Normalize(); } const float maxRelaxSpeed = 1.0f; f32 delta; if(gEnv->pPhysicalWorld->RayWorldIntersection(start, 1000.0f*dir, ent_all, rwi_pierceability(10)|rwi_ignore_back_faces, &hit, 1, pSkipEntities, nSkip)) { delta = g_pGameCVars->g_dof_minHitScale*hit.dist - m_minDoF; Limit(delta, -g_pGameCVars->g_dof_minAdjustSpeed, g_pGameCVars->g_dof_minAdjustSpeed); //delta *= fabs(delta/minAdjustSpeed); m_minDoF += delta * frameTime; delta = g_pGameCVars->g_dof_maxHitScale*hit.dist - m_maxDoF; Limit(delta, -g_pGameCVars->g_dof_maxAdjustSpeed, g_pGameCVars->g_dof_maxAdjustSpeed); //delta *= fabs(delta/maxAdjustSpeed); m_maxDoF += delta * frameTime; } if(m_maxDoF - g_pGameCVars->g_dof_distAppart < m_minDoF) { m_maxDoF = m_minDoF + g_pGameCVars->g_dof_distAppart; } else { // relax max to min delta = m_minDoF - m_maxDoF; Limit(delta, -maxRelaxSpeed, maxRelaxSpeed); //delta *= fabs(delta/maxRelaxSpeed); m_maxDoF += delta * frameTime; } // the average is relaxed to the center between min and max m_averageDoF = (m_maxDoF - m_minDoF)/2.0f; Limit(delta, -g_pGameCVars->g_dof_averageAdjustSpeed, g_pGameCVars->g_dof_averageAdjustSpeed); //delta *= fabs(delta/averageAdjustSpeed); m_averageDoF += delta * frameTime; } } }
void PID_LineCfg(uint16_t currLine, uint16_t setLine, PID_Config *config) { int32_t pid, speed, speedL, speedR; #if PID_DEBUG unsigned char buf[16]; static uint8_t cnt = 0; #endif uint8_t errorPercent; MOT_Direction directionL=MOT_DIR_FORWARD, directionR=MOT_DIR_FORWARD; pid = PID(currLine, setLine, config); errorPercent = errorWithinPercent(currLine-setLine); /* transform into different speed for motors. The PID is used as difference value to the motor PWM */ if (errorPercent <= 20) { /* pretty on center: move forward both motors with base speed */ speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100); /* 100% */ pid = Limit(pid, -speed, speed); if (pid<0) { /* turn right */ speedR = speed; speedL = speed-pid; } else { /* turn left */ speedR = speed+pid; speedL = speed; } } else if (errorPercent <= 40) { /* outside left/right halve position from center, slow down one motor and speed up the other */ speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100)*8/10; /* 80% */ pid = Limit(pid, -speed, speed); if (pid<0) { /* turn right */ speedR = speed+pid; /* decrease speed */ speedL = speed-pid; /* increase speed */ } else { /* turn left */ speedR = speed+pid; /* increase speed */ speedL = speed-pid; /* decrease speed */ } } else if (errorPercent <= 70) { speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100)*6/10; /* %60 */ pid = Limit(pid, -speed, speed); if (pid<0) { /* turn right */ speedR = 0 /*maxSpeed+pid*/; /* decrease speed */ speedL = speed-pid; /* increase speed */ } else { /* turn left */ speedR = speed+pid; /* increase speed */ speedL = 0 /*maxSpeed-pid*/; /* decrease speed */ } } else { /* line is far to the left or right: use backward motor motion */ speed = ((int32_t)config->maxSpeedPercent)*(0xffff/100)*10/10; /* %80 */ if (pid<0) { /* turn right */ speedR = -speed+pid; /* decrease speed */ speedL = speed-pid; /* increase speed */ } else { /* turn left */ speedR = speed+pid; /* increase speed */ speedL = -speed-pid; /* decrease speed */ } speedL = Limit(speedL, -speed, speed); speedR = Limit(speedR, -speed, speed); directionL = AbsSpeed(&speedL); directionR = AbsSpeed(&speedR); } /* speed is now always positive, make sure it is within 16bit PWM boundary */ if (speedL>0xFFFF) { speedL = 0xFFFF; } else if (speedL<0) { speedL = 0; } if (speedR>0xFFFF) { speedR = 0xFFFF; } else if (speedR<0) { speedR = 0; } /* send new speed values to motor */ MOT_SetVal(MOT_GetMotorHandle(MOT_MOTOR_LEFT), 0xFFFF-speedL); /* PWM is low active */ MOT_SetDirection(MOT_GetMotorHandle(MOT_MOTOR_LEFT), directionL); MOT_SetVal(MOT_GetMotorHandle(MOT_MOTOR_RIGHT), 0xFFFF-speedR); /* PWM is low active */ MOT_SetDirection(MOT_GetMotorHandle(MOT_MOTOR_RIGHT), directionR); #if PID_DEBUG /* debug diagnostic */ { cnt++; if (cnt>10) { /* limit number of messages to the console */ CLS1_StdIO_OutErr_FctType ioOut = CLS1_GetStdio()->stdOut; cnt = 0; CLS1_SendStr((unsigned char*)"line:", ioOut); buf[0] = '\0'; UTIL1_strcatNum16u(buf, sizeof(buf), currLine); CLS1_SendStr(buf, ioOut); CLS1_SendStr((unsigned char*)" sum:", ioOut); buf[0] = '\0'; UTIL1_strcatNum32Hex(buf, sizeof(buf), integral); CLS1_SendStr(buf, ioOut); CLS1_SendStr((unsigned char*)" left:", ioOut); CLS1_SendStr(directionL==MOT_DIR_FORWARD?(unsigned char*)"fw ":(unsigned char*)"bw ", ioOut); buf[0] = '\0'; UTIL1_strcatNum16Hex(buf, sizeof(buf), speedL); CLS1_SendStr(buf, ioOut); CLS1_SendStr((unsigned char*)" right:", ioOut); CLS1_SendStr(directionR==MOT_DIR_FORWARD?(unsigned char*)"fw ":(unsigned char*)"bw ", ioOut); buf[0] = '\0'; UTIL1_strcatNum16Hex(buf, sizeof(buf), speedR); CLS1_SendStr(buf, ioOut); CLS1_SendStr((unsigned char*)"\r\n", ioOut); } } #endif }
void CCtrlGeneral::OnVScroll(UINT code, UINT pos, CScrollBar *pscroll) //-------------------------------------------------------------------- { CDialog::OnVScroll(code, pos, pscroll); if (m_bInitialized) { CSliderCtrl* pSlider = (CSliderCtrl*) pscroll; if (pSlider == &m_SliderTempo) { const TEMPO tempo = tempoMax - TEMPO(m_SliderTempo.GetPos(), 0); if ((tempo >= m_sndFile.GetModSpecifications().GetTempoMin()) && (tempo <= m_sndFile.GetModSpecifications().GetTempoMax()) && (tempo != m_sndFile.m_nDefaultTempo)) { m_sndFile.m_nDefaultTempo = m_sndFile.m_PlayState.m_nMusicTempo = tempo; m_modDoc.SetModified(); m_modDoc.UpdateAllViews(nullptr, GeneralHint().General(), this); } } else if (pSlider == &m_SliderGlobalVol) { const UINT gv = MAX_SLIDER_GLOBAL_VOL - m_SliderGlobalVol.GetPos(); if ((gv >= 0) && (gv <= MAX_SLIDER_GLOBAL_VOL) && (gv != m_sndFile.m_nDefaultGlobalVolume)) { m_sndFile.m_PlayState.m_nGlobalVolume = gv; m_sndFile.m_nDefaultGlobalVolume = gv; m_modDoc.SetModified(); m_modDoc.UpdateAllViews(nullptr, GeneralHint().General(), this); } } else if (pSlider == &m_SliderSamplePreAmp) { const UINT spa = MAX_SLIDER_SAMPLE_VOL - m_SliderSamplePreAmp.GetPos(); if ((spa >= 0) && (spa <= MAX_SLIDER_SAMPLE_VOL) && (spa != m_sndFile.m_nSamplePreAmp)) { m_sndFile.m_nSamplePreAmp = spa; if(m_sndFile.GetType() != MOD_TYPE_MOD) m_modDoc.SetModified(); m_modDoc.UpdateAllViews(nullptr, GeneralHint().General(), this); } } else if (pSlider == &m_SliderVSTiVol) { const UINT vv = MAX_SLIDER_VSTI_VOL - m_SliderVSTiVol.GetPos(); if ((vv >= 0) && (vv <= MAX_SLIDER_VSTI_VOL) && (vv != m_sndFile.m_nVSTiVolume)) { m_sndFile.m_nVSTiVolume = vv; m_sndFile.RecalculateGainForAllPlugs(); m_modDoc.SetModified(); m_modDoc.UpdateAllViews(nullptr, GeneralHint().General(), this); } } else if(pSlider == (CSliderCtrl*)&m_SpinTempo) { int pos32 = m_SpinTempo.GetPos32(); if(pos32 != 0) { TEMPO newTempo; if(m_sndFile.GetModSpecifications().hasFractionalTempo) { pos32 *= TEMPO::fractFact; if(CMainFrame::GetMainFrame()->GetInputHandler()->CtrlPressed()) pos32 /= 100; else pos32 /= 10; newTempo.SetRaw(pos32); } else { newTempo = TEMPO(pos32, 0); } newTempo += m_sndFile.m_nDefaultTempo; Limit(newTempo, tempoMin, tempoMax); m_sndFile.m_nDefaultTempo = m_sndFile.m_PlayState.m_nMusicTempo = newTempo; m_modDoc.SetModified(); LockControls(); m_modDoc.UpdateAllViews(nullptr, GeneralHint().General(), this); UnlockControls(); } m_SpinTempo.SetPos(0); } UpdateView(GeneralHint().General()); } }
void DriveTrain::SetDrive_Auto(float turn, float throttle) { float tx, ty; tx = Limit(turn); ty = Limit(throttle); printf("Auto Drive: Turn %f Throttle %f ::",tx,ty); if (rightMaster->GetControlMode() != CANSpeedController::kPercentVbus) { positioning = false; Set_VoltageMode(); } if (ty > 0.0) { if (tx > 0.0) { leftMotorOutput = ty - tx; rightMotorOutput = std::max(ty, tx); } else if (tx < 0.0) { leftMotorOutput = std::max(ty, -tx); rightMotorOutput = ty + tx; } else { leftMotorOutput = ty; rightMotorOutput = ty; } } else { if (tx > 0.0) { leftMotorOutput = - std::max(-ty, tx); rightMotorOutput = ty + tx; } else if (tx < 0.0) { leftMotorOutput = ty - tx; rightMotorOutput = - std::max(-ty, -tx); } else { leftMotorOutput = ty; rightMotorOutput = ty; } } leftMaster->Set(leftMotorOutput); rightMaster->Set(rightMotorOutput); float lt1v = leftTalon1->GetOutputVoltage(); float lt1c = leftTalon1->GetOutputCurrent(); float lt2v = leftTalon2->GetOutputVoltage(); float lt2c = leftTalon2->GetOutputCurrent(); float rt1v = rightTalon1->GetOutputVoltage(); float rt1c = rightTalon1->GetOutputCurrent(); float rt2v = rightTalon2->GetOutputVoltage(); float rt2c = rightTalon2->GetOutputCurrent(); float PDP0 = 0; float PDP1 = 0; float PDP14 = 0; float PDP15 = 0; if (RobotMap::pDPPowerDistributionPanel.get() != nullptr) { PDP0 = RobotMap::pDPPowerDistributionPanel->GetCurrent(0); PDP1 = RobotMap::pDPPowerDistributionPanel->GetCurrent(1); PDP14 = RobotMap::pDPPowerDistributionPanel->GetCurrent(14); PDP15 = RobotMap::pDPPowerDistributionPanel->GetCurrent(15); } printf(" l1(CAN 1/PDP 15) PdpC %f : V %f : C %f :: l2 (CAN 2/PDP 14) PdpC %f : V %f : C %f :: r1(CAN 3/PDP 0) PdpC %f : V %f : C %f :: r2(CAN 4/PDP 1) PdpC %f : V %f : C %f \n", PDP15, lt1v, lt1c, PDP14, lt2v, lt2c, PDP0, rt1v, rt1c, PDP1, rt2v, rt2c); }
void DriveTrain::SetDrive_Split(float turn, float throttle, bool highRate) { float tx, ty; tx = Limit(turn); ty = Limit(throttle); printf("Split Drive: Turn %f : Throttle %f :: ",tx,ty); if (rightMaster->GetControlMode() != CANSpeedController::kPercentVbus) { positioning = false; Set_VoltageMode(); } if (ty > 0.0) // If moving Forward { if (tx > 0.0) // If turning/rotating right { leftMotorOutput = ty - tx; rightMotorOutput = std::max(ty, tx); } else if (tx < 0.0) // If turning/rotating left or not moving { leftMotorOutput = std::max(ty, -tx); rightMotorOutput = ty + tx; } else { leftMotorOutput = ty; rightMotorOutput = ty; } } else // If Moving Backward { if (tx > 0.0) // If turning/rotating right { leftMotorOutput = - std::max(-ty, tx); rightMotorOutput = ty + tx; } else if (tx < 0.0) // If turning/rotating left or not moving { leftMotorOutput = ty - tx; rightMotorOutput = - std::max(-ty, -tx); } else { leftMotorOutput = ty; rightMotorOutput = ty; } } if (highRate) // Technically high rate is the new slow for Stronghold. Will change this in the off season. { leftMaster->Set(leftMotorOutput*myCfg->HighSpeed); rightMaster->Set(rightMotorOutput*myCfg->HighSpeed); } else { leftMaster->Set(leftMotorOutput*myCfg->LowSpeed); rightMaster->Set(rightMotorOutput*myCfg->LowSpeed); } float lt1v = leftTalon1->GetOutputVoltage(); float lt1c = leftTalon1->GetOutputCurrent(); float lt2v = leftTalon2->GetOutputVoltage(); float lt2c = leftTalon2->GetOutputCurrent(); float rt1v = rightTalon1->GetOutputVoltage(); float rt1c = rightTalon1->GetOutputCurrent(); float rt2v = rightTalon2->GetOutputVoltage(); float rt2c = rightTalon2->GetOutputCurrent(); float PDP0 = 0; float PDP1 = 0; float PDP14 = 0; float PDP15 = 0; if (RobotMap::pDPPowerDistributionPanel.get() != nullptr) { PDP0 = RobotMap::pDPPowerDistributionPanel->GetCurrent(0); PDP1 = RobotMap::pDPPowerDistributionPanel->GetCurrent(1); PDP14 = RobotMap::pDPPowerDistributionPanel->GetCurrent(14); PDP15 = RobotMap::pDPPowerDistributionPanel->GetCurrent(15); } printf(" l1(CAN 1/PDP 15) PdpC %f : V %f : C %f :: l2 (CAN 2/PDP 14) PdpC %f : V %f : C %f :: r1(CAN 3/PDP 0) PdpC %f : V %f : C %f :: r2(CAN 4/PDP 1) PdpC %f : V %f : C %f \n", PDP15, lt1v, lt1c, PDP14, lt2v, lt2c, PDP0, rt1v, rt1c, PDP1, rt2v, rt2c); }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementTank::ProcessMovement(const float deltaTime) { FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME ); m_netActionSync.UpdateObject(this); CryAutoCriticalSection lk(m_lock); CVehicleMovementBase::ProcessMovement(deltaTime); if (!(m_actorId && m_isEnginePowered)) { IPhysicalEntity* pPhysics = GetPhysics(); if (m_latFriction != 1.3f) SetLatFriction(1.3f); if (m_axleFriction != m_axleFrictionMax) UpdateAxleFriction(0.f, false, deltaTime); m_action.bHandBrake = 1; m_action.pedal = 0; m_action.steer = 0; pPhysics->Action(&m_action, 1); return; } IPhysicalEntity* pPhysics = GetPhysics(); MARK_UNUSED m_action.clutch; Matrix34 worldTM( m_PhysPos.q ); worldTM.AddTranslation( m_PhysPos.pos ); const Matrix34 invWTM = worldTM.GetInvertedFast(); Vec3 localVel = invWTM.TransformVector(m_PhysDyn.v); Vec3 localW = invWTM.TransformVector(m_PhysDyn.w); float speed = m_PhysDyn.v.len(); float speedRatio = min(1.f, speed/m_maxSpeed); float actionPedal = abs(m_movementAction.power) > 0.001f ? m_movementAction.power : 0.f; // tank specific: // avoid steering input around 0.5 (ask Anton) float actionSteer = m_movementAction.rotateYaw; float absSteer = abs(actionSteer); float steerSpeed = (absSteer < 0.01f && abs(m_currSteer) > 0.01f) ? m_steerSpeedRelax : m_steerSpeed; if (steerSpeed == 0.f) { m_currSteer = (float)sgn(actionSteer); } else { if (m_movementAction.isAI) { m_currSteer = actionSteer; } else { m_currSteer += min(abs(actionSteer-m_currSteer), deltaTime*steerSpeed) * sgn(actionSteer-m_currSteer); } } Limit(m_currSteer, -m_steerLimit, m_steerLimit); if (abs(m_currSteer) > 0.0001f) { // if steering, apply full throttle to have enough turn power actionPedal = (float)sgn(actionPedal); if (actionPedal == 0.f) { // allow steering-on-teh-spot only above maxReverseSpeed (to avoid sudden reverse of controls) const float maxReverseSpeed = -1.5f; actionPedal = max(0.f, min(1.f, 1.f-(localVel.y/maxReverseSpeed))); // todo float steerLim = 0.8f; Limit(m_currSteer, -steerLim*m_steerLimit, steerLim*m_steerLimit); } } if (!pPhysics->GetStatus(&m_vehicleStatus)) return; int currGear = m_vehicleStatus.iCurGear - 1; // indexing for convenience: -1,0,1,2,.. UpdateAxleFriction(m_movementAction.power, true, deltaTime); UpdateSuspension(deltaTime); float absPedal = abs(actionPedal); // pedal ramping if (m_pedalSpeed == 0.f) m_currPedal = actionPedal; else { m_currPedal += deltaTime * m_pedalSpeed * sgn(actionPedal - m_currPedal); m_currPedal = clamp_tpl(m_currPedal, -absPedal, absPedal); } // only apply pedal after threshold is exceeded if (currGear == 0 && fabs_tpl(m_currPedal) < m_pedalThreshold) m_action.pedal = 0; else m_action.pedal = m_currPedal; // change pedal amount based on damages float damageMul = 0.0f; { if (m_movementAction.isAI) { damageMul = 1.0f - 0.30f * m_damage; m_action.pedal *= damageMul; } else { // request from Sten: damage shouldn't affect reversing so much. float effectiveDamage = m_damage; if(m_action.pedal < -0.1f) effectiveDamage = 0.4f * m_damage; m_action.pedal *= GetWheelCondition(); damageMul = 1.0f - 0.7f*effectiveDamage; m_action.pedal *= damageMul; } } // reverse steering value for backward driving float effSteer = m_currSteer * sgn(actionPedal); // update lateral friction float latSlipMinGoal = 0.f; float latFricMinGoal = m_latFricMin; if (abs(effSteer) > 0.01f && !m_movementAction.brake) { latSlipMinGoal = m_latSlipMin; // use steering friction, but not when countersteering if (sgn(effSteer) != sgn(localW.z)) latFricMinGoal = m_latFricMinSteer; } Interpolate(m_currentSlipMin, latSlipMinGoal, 3.f, deltaTime); if (latFricMinGoal < m_currentFricMin) m_currentFricMin = latFricMinGoal; else Interpolate(m_currentFricMin, latFricMinGoal, 3.f, deltaTime); float fractionSpeed = min(1.f, max(0.f, m_avgLateralSlip-m_currentSlipMin) / (m_latSlipMax-m_currentSlipMin)); float latFric = fractionSpeed * (m_latFricMax-m_currentFricMin) + m_currentFricMin; if ( m_movementAction.brake && m_movementAction.isAI ) { // it is natural for ai, apply differnt friction value while handbreaking latFric = m_latFricMax; } if (latFric != m_latFriction) { SetLatFriction(latFric); } const static float maxSteer = gf_PI/4.f; // fix maxsteer, shouldn't change m_action.steer = m_currSteer * maxSteer; if (m_steeringImpulseMin > 0.f && m_wheelContactsLeft != 0 && m_wheelContactsRight != 0) { const float maxW = 0.3f*gf_PI; float steer = abs(m_currSteer)>0.001f ? m_currSteer : 0.f; float desired = steer * maxW; float curr = -localW.z; float err = desired - curr; // err>0 means correction to right Limit(err, -maxW, maxW); if (abs(err) > 0.01f) { float amount = m_steeringImpulseMin + speedRatio*(m_steeringImpulseMax-m_steeringImpulseMin); // bigger correction for relaxing if (desired == 0.f || (desired*curr>0 && abs(desired)<abs(curr))) amount = m_steeringImpulseRelaxMin + speedRatio*(m_steeringImpulseRelaxMax-m_steeringImpulseRelaxMin); float corr = -err * amount * m_PhysDyn.mass * deltaTime; pe_action_impulse imp; imp.iApplyTime = 0; imp.angImpulse = worldTM.GetColumn2() * corr; pPhysics->Action(&imp, THREAD_SAFE); } } m_action.bHandBrake = (m_movementAction.brake) ? 1 : 0; if (currGear > 0 && m_vehicleStatus.iCurGear < m_currentGear) { // when shifted down, disengage clutch immediately to avoid power/speed dropdown m_action.clutch = 1.f; } pPhysics->Action(&m_action, 1); if (Boosting()) ApplyBoost(speed, 1.2f*m_maxSpeed*GetWheelCondition()*damageMul, m_boostStrength, deltaTime); if (m_wheelContacts <= 1 && speed > 5.f) { ApplyAirDamp(DEG2RAD(20.f), DEG2RAD(10.f), deltaTime, THREAD_SAFE); UpdateGravity(-9.81f * 1.4f); } if (m_netActionSync.PublishActions( CNetworkMovementStdWheeled(this) )) CHANGED_NETWORK_STATE(m_pVehicle, eEA_GameClientDynamic ); }
//------------------------------------------------------------------------ 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& currentPitch = angles.x; // +ve roll means to the left const float& currentRoll = 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); }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementTank::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); float dt = max( deltaTime, 0.005f); m_movementAction.brake = false; m_movementAction.rotateYaw = 0.0f; m_movementAction.power = 0.0f; float inputSpeed = 0.0f; { if (m_aiRequest.HasDesiredSpeed()) inputSpeed = m_aiRequest.GetDesiredSpeed(); Limit(inputSpeed, -m_maxSpeed, m_maxSpeed); } Vec3 vMove(ZERO); { if (m_aiRequest.HasMoveTarget()) vMove = ( m_aiRequest.GetMoveTarget() - m_PhysPos.pos ).GetNormalizedSafe(); } //start calculation if ( fabsf( inputSpeed ) < 0.0001f || m_tireBlownTimer > 1.5f ) { // only the case to use a hand break m_movementAction.brake = true; } else { Matrix33 entRotMatInvert( m_PhysPos.q ); entRotMatInvert.Invert(); float currentAngleSpeed = RAD2DEG(-m_PhysDyn.w.z); const static float maxSteer = RAD2DEG(gf_PI/4.f); // fix maxsteer, shouldn't change Vec3 vVel = m_PhysDyn.v; Vec3 vVelR = entRotMatInvert * vVel; float currentSpeed =vVel.GetLength(); vVelR.NormalizeSafe(); if ( vVelR.Dot( FORWARD_DIRECTION ) < 0 ) currentSpeed *= -1.0f; // calculate pedal static float accScale = 0.5f; m_movementAction.power = (inputSpeed - currentSpeed) * accScale; Limit( m_movementAction.power, -1.0f, 1.0f); // calculate angles Vec3 vMoveR = entRotMatInvert * vMove; Vec3 vFwd = FORWARD_DIRECTION; vMoveR.z =0.0f; vMoveR.NormalizeSafe(); if ( inputSpeed < 0.0 ) // when going back { vFwd *= -1.0f; vMoveR *= -1.0f; currentAngleSpeed *=-1.0f; } float cosAngle = vFwd.Dot(vMoveR); float angle = RAD2DEG( acos_tpl(cosAngle)); if ( vMoveR.Dot( Vec3( 1.0f,0.0f,0.0f ) )< 0 ) angle = -angle; // int step =0; m_movementAction.rotateYaw = angle * 1.75f/ maxSteer; // implementation 1. if there is enough angle speed, we don't need to steer more if ( fabsf(currentAngleSpeed) > fabsf(angle) && angle*currentAngleSpeed > 0.0f ) { m_movementAction.rotateYaw = m_currSteer*0.995f; // step =1; } // implementation 2. if we can guess we reach the distination angle soon, start counter steer. float predictDelta = inputSpeed < 0.0f ? 0.1f : 0.07f; float dict = angle + predictDelta * ( angle - m_prevAngle) / dt ; if ( dict*currentAngleSpeed<0.0f ) { if ( fabsf( angle ) < 2.0f ) { m_movementAction.rotateYaw = angle* 1.75f/ maxSteer; // step =3; } else { m_movementAction.rotateYaw = currentAngleSpeed < 0.0f ? 1.0f : -1.0f; // step =2; } } // implementation 3. tank can rotate at a point if ( fabs( angle )> 20.0f ) { m_movementAction.power *=0.1f; // step =4; } // char buf[1024]; // sprintf(buf, "steering %4.2f %4.2f %4.2f %d\n", deltaTime,currentAngleSpeed, angle - m_prevAngle, step); // OutputDebugString( buf ); m_prevAngle = angle; } }
////////////////////////////////////////////////////////////////////////// // 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); }
// Merge assertions on the edge flowing into the block about a variable. void RangeCheck::MergeEdgeAssertions(GenTreePtr tree, EXPSET_TP assertions, Range* pRange) { if (assertions == 0) { return; } GenTreeLclVarCommon* lcl = (GenTreeLclVarCommon*) tree; if (lcl->gtSsaNum == SsaConfig::RESERVED_SSA_NUM) { return; } // Walk through the "assertions" to check if the apply. unsigned index = 1; for (EXPSET_TP mask = 1; index <= m_pCompiler->GetAssertionCount(); index++, mask <<= 1) { if ((assertions & mask) == 0) { continue; } Compiler::AssertionDsc* curAssertion = m_pCompiler->optGetAssertion(index); // Current assertion is about array length. if (!curAssertion->IsArrLenArithBound() && !curAssertion->IsArrLenBound()) { continue; } #ifdef DEBUG if (m_pCompiler->verbose) { m_pCompiler->optPrintAssertion(curAssertion, index); } #endif assert(m_pCompiler->vnStore->IsVNArrLenArithBound(curAssertion->op1.vn) || m_pCompiler->vnStore->IsVNArrLenBound(curAssertion->op1.vn)); ValueNumStore::ArrLenArithBoundInfo info; Limit limit(Limit::keUndef); // Current assertion is of the form (i < a.len - cns) != 0 if (curAssertion->IsArrLenArithBound()) { // Get i, a.len, cns and < as "info." m_pCompiler->vnStore->GetArrLenArithBoundInfo(curAssertion->op1.vn, &info); if (m_pCompiler->lvaTable[lcl->gtLclNum].GetPerSsaData(lcl->gtSsaNum)->m_vnPair.GetConservative() != info.cmpOp) { continue; } switch (info.arrOper) { case GT_SUB: case GT_ADD: { // If the operand that operates on the array is not constant, then done. if (!m_pCompiler->vnStore->IsVNConstant(info.arrOp) || m_pCompiler->vnStore->TypeOfVN(info.arrOp) != TYP_INT) { break; } int cons = m_pCompiler->vnStore->ConstantValue<int>(info.arrOp); limit = Limit(Limit::keBinOpArray, info.vnArray, info.arrOper == GT_SUB ? -cons : cons); } } } // Current assertion is of the form (i < a.len) != 0 else if (curAssertion->IsArrLenBound()) { // Get the info as "i", "<" and "a.len" m_pCompiler->vnStore->GetArrLenBoundInfo(curAssertion->op1.vn, &info); ValueNum lclVn = m_pCompiler->lvaTable[lcl->gtLclNum].GetPerSsaData(lcl->gtSsaNum)->m_vnPair.GetConservative(); // If we don't have the same variable we are comparing against, bail. if (lclVn != info.cmpOp) { continue; } limit.type = Limit::keArray; limit.vn = info.vnArray; } else { noway_assert(false); } if (limit.IsUndef()) { continue; } // Make sure the assertion is of the form != 0 or == 0. if (curAssertion->op2.vn != m_pCompiler->vnStore->VNZeroForType(TYP_INT)) { continue; } #ifdef DEBUG if (m_pCompiler->verbose) m_pCompiler->optPrintAssertion(curAssertion, index); #endif noway_assert(limit.IsBinOpArray() || limit.IsArray()); ValueNum arrLenVN = m_pCurBndsChk->gtArrLen->gtVNPair.GetConservative(); ValueNum arrRefVN = m_pCompiler->vnStore->GetArrForLenVn(arrLenVN); // During assertion prop we add assertions of the form: // // (i < a.Length) == 0 // (i < a.Length) != 0 // // At this point, we have detected that op1.vn is (i < a.Length) or (i < a.Length + cns), // and the op2.vn is 0. // // Now, let us check if we are == 0 (i.e., op1 assertion is false) or != 0 (op1 assertion // is true.), // // If we have an assertion of the form == 0 (i.e., equals false), then reverse relop. // The relop has to be reversed because we have: (i < a.Length) is false which is the same // as (i >= a.Length). genTreeOps cmpOper = (genTreeOps) info.cmpOper; if (curAssertion->assertionKind == Compiler::OAK_EQUAL) { cmpOper = GenTree::ReverseRelop(cmpOper); } // Bounds are inclusive, so add -1 for upper bound when "<". But make sure we won't overflow. if (cmpOper == GT_LT && !limit.AddConstant(-1)) { continue; } // Bounds are inclusive, so add +1 for lower bound when ">". But make sure we won't overflow. if (cmpOper == GT_GT && !limit.AddConstant(1)) { continue; } // Doesn't tighten the current bound. So skip. if (pRange->uLimit.IsConstant() && limit.vn != arrRefVN) { continue; } // Check if the incoming limit from assertions tightens the existing upper limit. if ((pRange->uLimit.IsArray() || pRange->uLimit.IsBinOpArray()) && pRange->uLimit.vn == arrRefVN) { // We have checked the current range's (pRange's) upper limit is either of the form: // a.Length // a.Length + cns // and a == the bndsChkCandidate's arrRef // // We want to check if the incoming limit tightens the bound, and for that the // we need to make sure that incoming limit is also on a.Length or a.Length + cns // and not b.Length or some c.Length. if (limit.vn != arrRefVN) { JITDUMP("Array ref did not match cur=$%x, assert=$%x\n", arrRefVN, limit.vn); continue; } int curCns = (pRange->uLimit.IsBinOpArray()) ? pRange->uLimit.cns : 0; int limCns = (limit.IsBinOpArray()) ? limit.cns : 0; // Incoming limit doesn't tighten the existing upper limit. if (limCns >= curCns) { JITDUMP("Bound limit %d doesn't tighten current bound %d\n", limCns, curCns); continue; } } else { // Current range's upper bound is not "a.Length or a.Length + cns" and the // incoming limit is not on the same arrRef as the bounds check candidate. // So we could skip this assertion. But in cases, of Dependent or Unknown // type of upper limit, the incoming assertion still tightens the upper // bound to a saner value. So do not skip the assertion. } // cmpOp (loop index i) cmpOper a.len +/- cns switch (cmpOper) { case GT_LT: pRange->uLimit = limit; break; case GT_GT: pRange->lLimit = limit; break; case GT_GE: pRange->lLimit = limit; break; case GT_LE: pRange->uLimit = limit; break; } JITDUMP("The range after edge merging:"); JITDUMP(pRange->ToString(m_pCompiler->getAllocatorDebugOnly())); JITDUMP("\n"); } }
//------------------------------------------------------------------------ void CVehicleViewSteer::Update(float dt) { IEntity* pEntity = m_pVehicle->GetEntity(); assert(pEntity); IVehicleMovement* pVehicleMovement = m_pVehicle->GetMovement(); if (pVehicleMovement == NULL) return; IPhysicalEntity* pPhysEntity = pEntity->GetPhysics(); if (!pPhysEntity) return; pe_status_dynamics dynStatus; pPhysEntity->GetStatus(&dynStatus); SMovementState movementState; pVehicleMovement->GetMovementState(movementState); const float pedal = pVehicleMovement->GetEnginePedal(); const float maxSpeed = movementState.maxSpeed; const Matrix34 &pose = m_pAimPart ? m_pAimPart->GetWorldTM() : pEntity->GetWorldTM(); const Vec3 entityPos = pose.GetColumn3(); const Vec3 xAxis = pose.GetColumn0(); const Vec3 yAxis = pose.GetColumn1(); const Vec3 zAxis = pose.GetColumn2(); const float forwardSpeed = dynStatus.v.dot(yAxis); const float speedNorm = clamp_tpl(forwardSpeed / maxSpeed, 0.0f, 1.0f); const Vec3 maxRotation = m_maxRotation + speedNorm * (m_maxRotation2 - m_maxRotation); CalcLookAt(pose); if (m_lookAt.IsValid()) { if (!m_lastOffset.IsValid()) { m_position = pose * m_localSpaceCameraOffset; m_lastOffset = m_position - m_lookAt; m_lastOffsetBeforeElev = m_lastOffset; } Vec3 offset = m_lastOffsetBeforeElev; if (pedal < 0.1f && forwardSpeed < 1.0f) { // Going Backwards m_flags &= ~(eVCam_goingForwards | m_forwardFlags); m_flags |= m_backwardsFlags; } if (offset.dot(yAxis) < 0.8f && forwardSpeed > 1.f) { // Going Forwards m_flags &= ~m_backwardsFlags; m_flags |= eVCam_goingForwards | m_forwardFlags; } float sensitivity = (1.f - speedNorm) * m_stickSensitivity.z + speedNorm * m_stickSensitivity2.z; float rotate = -m_rotatingAction.z * sensitivity; rotate = rotate * dt; if (zAxis.z > 0.1f) { // Safe to update curYaw Vec3 projectedX = xAxis; projectedX.z = 0.f; Vec3 projectedY = yAxis; projectedY.z = 0.f; const float newYaw = atan2_tpl(offset.dot(projectedX), -(offset.dot(projectedY))); const float maxChange = DEG2RAD(270.f) * dt; const float delta = clamp_tpl(newYaw - m_curYaw, -maxChange, +maxChange); m_curYaw += delta; } // Rotation Action { if (m_flags & eVCam_rotationClamp) { float newYaw = clamp_tpl(m_curYaw + rotate, -maxRotation.z, +maxRotation.z); rotate = newYaw - m_curYaw; rotate = clamp_tpl(newYaw - m_curYaw, -fabsf(rotate), +fabsf(rotate)); m_rotation.z += rotate; } else { m_rotation.z = 0.f; } if (speedNorm > 0.1f) { float reduce = dt * 1.f; m_rotation.z = m_rotation.z - reduce * m_rotation.z / (fabsf(m_rotation.z) + reduce); } } // Ang Spring { float angSpeedCorrection = dt * dt * m_angSpeedCorrection / (dt * m_angSpeedCorrection + 1.f) * dynStatus.w.z; if ((m_flags & eVCam_rotationSpring) == 0) { m_angReturnSpeed = 0.f; angSpeedCorrection = 0.f; } float difference = m_rotation.z - m_curYaw; float relax = difference * (m_angReturnSpeed * dt) / ((m_angReturnSpeed * dt) + 1.f); const float delta = +relax + angSpeedCorrection + rotate; m_curYaw += delta; Matrix33 rot = Matrix33::CreateRotationZ(delta); offset = rot * offset; // Lerp the spring speed float angSpeedTarget = m_angReturnSpeed1 + speedNorm * (m_angReturnSpeed2 - m_angReturnSpeed1); m_angReturnSpeed += (angSpeedTarget - m_angReturnSpeed) * (dt / (dt + 0.3f)); m_angSpeedCorrection += (m_angSpeedCorrection0 - m_angSpeedCorrection) * (dt / (dt + 0.3f)); } if (!offset.IsValid()) offset = m_lastOffset; // Velocity influence Vec3 displacement = -((2.f - speedNorm) * dt) * dynStatus.v;// - yAxis*(0.0f*speedNorm*(yAxis.dot(dynStatus.v)))); float dot = offset.dot(displacement); if (dot < 0.f) { displacement = displacement + offset * -0.1f * (offset.dot(displacement) / offset.GetLengthSquared()); } offset = offset + displacement; const float radius0 = fabsf(m_localSpaceCameraOffset.y); const float minRadius = radius0 * m_radiusMin; const float maxRadius = radius0 * m_radiusMax; float radiusXY = sqrtf(sqr(offset.x) + sqr(offset.y)); Vec3 offsetXY = offset; offsetXY.z = 0.f; Vec3 accelerationV = (dynStatus.v - m_lastVehVel); float acceleration = offsetXY.dot(accelerationV) / radiusXY; m_lastVehVel = dynStatus.v; m_radiusVel -= acceleration; m_radius += m_radiusVel * dt - dt * m_radiusVelInfluence * offsetXY.dot(dynStatus.v) / radiusXY; m_radiusVel *= expf(-dt * m_radiusDampRate); m_radius += (radius0 - m_radius) * (dt * m_radiusRelaxRate) / (dt * m_radiusRelaxRate + 1.f); m_radius = clamp_tpl(m_radius, minRadius, maxRadius); offset = offset * (m_radius / radiusXY); // Vertical motion float targetOffsetHeight = m_localSpaceCameraOffset.z * (m_radius / radius0); float oldOffsetHeight = offset.z; offset.z += (targetOffsetHeight - offset.z) * (dt / (dt + 0.3f)); Limit(offset.z, targetOffsetHeight - 2.f, targetOffsetHeight + 2.f); float verticalChange = offset.z - oldOffsetHeight; m_lastOffsetBeforeElev = offset; // Add up and down camera tilt { offset.z -= verticalChange; m_rotation.x += dt * m_stickSensitivity.x * m_rotatingAction.x; m_rotation.x = clamp_tpl(m_rotation.x, -maxRotation.x, +maxRotation.x); float elevAngleVehicle = m_inheritedElev * yAxis.z; // yAxis.z == approx elevation angle float elevationAngle = m_rotation.x - elevAngleVehicle; float sinElev, cosElev; sincos_tpl(elevationAngle, &sinElev, &cosElev); float horizLen = sqrtf(offset.GetLengthSquared2D()); float horizLenNew = horizLen * cosElev - sinElev * offset.z; if (horizLen > 1e-4f) { horizLenNew /= horizLen; offset.x *= horizLenNew; offset.y *= horizLenNew; offset.z = offset.z * cosElev + sinElev * horizLen; } offset.z += verticalChange; } if (!offset.IsValid()) offset = m_lastOffset; m_position = m_lookAt + offset; // Perform world intersection test. { // Initialise sphere and direction. primitives::sphere sphere; sphere.center = m_lookAt; sphere.r = g_SteerCameraRadius; Vec3 direction = m_position - m_lookAt; // Calculate camera bounds. AABB localBounds; m_pVehicle->GetEntity()->GetLocalBounds(localBounds); const float cameraBoundsScale = 0.75f; localBounds.min *= cameraBoundsScale; localBounds.max *= cameraBoundsScale; OBB cameraBounds; Matrix34 worldTM = m_pVehicle->GetEntity()->GetWorldTM(); cameraBounds.SetOBBfromAABB(Matrix33(worldTM), localBounds); // Try to find point on edge of camera bounds to begin swept sphere intersection test. Vec3 rayBoxIntersect; if (Intersect::Ray_OBB(Ray(m_position, -direction), worldTM.GetTranslation(), cameraBounds, rayBoxIntersect) > 0) { Vec3 temp = m_position - rayBoxIntersect; if (direction.Dot(temp) > 0.0f) { sphere.center = rayBoxIntersect; direction = temp; } } // Perform swept sphere intersection test against world. geom_contact* pContact = NULL; IPhysicalEntity* pSkipEntities[10]; float distance = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, direction, ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid, &pContact, 0, (geom_colltype_player << rwi_colltype_bit) | rwi_stop_at_pierceable, 0, 0, 0, pSkipEntities, m_pVehicle->GetSkipEntities(pSkipEntities, 10)); if (distance > 0.0f) { // Sweep intersects world so calculate new offset. offset = (sphere.center + (direction.GetNormalizedSafe() * distance)) - m_lookAt; } } Interpolate(m_lastOffset, offset, 10.f, dt); m_position = m_lookAt + m_lastOffset; } else { CRY_ASSERT_MESSAGE(0, "camera will fail because lookat position is invalid"); } m_rotatingAction.zero(); }
// Translate instrument properties between two given formats. void ModInstrument::Convert(MODTYPE fromType, MODTYPE toType) { MPT_UNREFERENCED_PARAMETER(fromType); if(toType & MOD_TYPE_XM) { ResetNoteMap(); PitchEnv.dwFlags.reset(ENV_ENABLED | ENV_FILTER); dwFlags.reset(INS_SETPANNING); SetCutoff(GetCutoff(), false); SetResonance(GetResonance(), false); nFilterMode = FLTMODE_UNCHANGED; nCutSwing = nPanSwing = nResSwing = nVolSwing = 0; nPPC = NOTE_MIDDLEC - 1; nPPS = 0; nNNA = NNA_NOTECUT; nDCT = DCT_NONE; nDNA = DNA_NOTECUT; if(nMidiChannel == MidiMappedChannel) { nMidiChannel = 1; } // FT2 only has unsigned Pitch Wheel Depth, and it's limited to 0...36 (in the GUI, at least. As you would expect it from FT2, this value is actually not sanitized on load). midiPWD = static_cast<int8>(mpt::abs(midiPWD)); Limit(midiPWD, int8(0), int8(36)); nGlobalVol = 64; nPan = 128; LimitMax(nFadeOut, 32767u); } VolEnv.Convert(fromType, toType); PanEnv.Convert(fromType, toType); PitchEnv.Convert(fromType, toType); if(fromType == MOD_TYPE_XM && (toType & (MOD_TYPE_IT | MOD_TYPE_MPT))) { if(!VolEnv.dwFlags[ENV_ENABLED]) { // Note-Off with no envelope cuts the note immediately in XM VolEnv.resize(2); VolEnv[0].tick = 0; VolEnv[0].value = ENVELOPE_MAX; VolEnv[1].tick = 1; VolEnv[1].value = ENVELOPE_MIN; VolEnv.dwFlags.set(ENV_ENABLED | ENV_SUSTAIN); VolEnv.dwFlags.reset(ENV_LOOP); VolEnv.nSustainStart = VolEnv.nSustainEnd = 0; } } // Limit fadeout length for IT if(toType & MOD_TYPE_IT) { LimitMax(nFadeOut, 8192u); } // MPT-specific features - remove instrument tunings, Pitch/Tempo Lock, cutoff / resonance swing and filter mode for other formats if(!(toType & MOD_TYPE_MPT)) { SetTuning(nullptr); pitchToTempoLock.Set(0); nCutSwing = nResSwing = 0; nFilterMode = FLTMODE_UNCHANGED; nVolRampUp = 0; } }
// Merge assertions on the edge flowing into the block about a variable. void RangeCheck::MergeEdgeAssertions(GenTreeLclVarCommon* lcl, ASSERT_VALARG_TP assertions, Range* pRange) { if (BitVecOps::IsEmpty(m_pCompiler->apTraits, assertions)) { return; } if (lcl->gtSsaNum == SsaConfig::RESERVED_SSA_NUM) { return; } // Walk through the "assertions" to check if the apply. BitVecOps::Iter iter(m_pCompiler->apTraits, assertions); unsigned index = 0; while (iter.NextElem(&index)) { AssertionIndex assertionIndex = GetAssertionIndex(index); Compiler::AssertionDsc* curAssertion = m_pCompiler->optGetAssertion(assertionIndex); Limit limit(Limit::keUndef); genTreeOps cmpOper = GT_NONE; LclSsaVarDsc* ssaData = m_pCompiler->lvaTable[lcl->gtLclNum].GetPerSsaData(lcl->gtSsaNum); ValueNum normalLclVN = m_pCompiler->vnStore->VNConservativeNormalValue(ssaData->m_vnPair); // Current assertion is of the form (i < len - cns) != 0 if (curAssertion->IsCheckedBoundArithBound()) { ValueNumStore::CompareCheckedBoundArithInfo info; // Get i, len, cns and < as "info." m_pCompiler->vnStore->GetCompareCheckedBoundArithInfo(curAssertion->op1.vn, &info); // If we don't have the same variable we are comparing against, bail. if (normalLclVN != info.cmpOp) { continue; } if ((info.arrOper != GT_ADD) && (info.arrOper != GT_SUB)) { continue; } // If the operand that operates on the bound is not constant, then done. if (!m_pCompiler->vnStore->IsVNInt32Constant(info.arrOp)) { continue; } int cons = m_pCompiler->vnStore->ConstantValue<int>(info.arrOp); limit = Limit(Limit::keBinOpArray, info.vnBound, info.arrOper == GT_SUB ? -cons : cons); cmpOper = (genTreeOps)info.cmpOper; } // Current assertion is of the form (i < len) != 0 else if (curAssertion->IsCheckedBoundBound()) { ValueNumStore::CompareCheckedBoundArithInfo info; // Get the info as "i", "<" and "len" m_pCompiler->vnStore->GetCompareCheckedBound(curAssertion->op1.vn, &info); // If we don't have the same variable we are comparing against, bail. if (normalLclVN != info.cmpOp) { continue; } limit = Limit(Limit::keBinOpArray, info.vnBound, 0); cmpOper = (genTreeOps)info.cmpOper; } // Current assertion is of the form (i < 100) != 0 else if (curAssertion->IsConstantBound()) { ValueNumStore::ConstantBoundInfo info; // Get the info as "i", "<" and "100" m_pCompiler->vnStore->GetConstantBoundInfo(curAssertion->op1.vn, &info); // If we don't have the same variable we are comparing against, bail. if (normalLclVN != info.cmpOpVN) { continue; } limit = Limit(Limit::keConstant, info.constVal); cmpOper = (genTreeOps)info.cmpOper; } // Current assertion is not supported, ignore it else { continue; } assert(limit.IsBinOpArray() || limit.IsConstant()); // Make sure the assertion is of the form != 0 or == 0. if (curAssertion->op2.vn != m_pCompiler->vnStore->VNZeroForType(TYP_INT)) { continue; } #ifdef DEBUG if (m_pCompiler->verbose) { m_pCompiler->optPrintAssertion(curAssertion, assertionIndex); } #endif ValueNum arrLenVN = m_pCompiler->vnStore->VNConservativeNormalValue(m_pCurBndsChk->gtArrLen->gtVNPair); if (m_pCompiler->vnStore->IsVNConstant(arrLenVN)) { // Set arrLenVN to NoVN; this will make it match the "vn" recorded on // constant limits (where we explicitly track the constant and don't // redundantly store its VN in the "vn" field). arrLenVN = ValueNumStore::NoVN; } // During assertion prop we add assertions of the form: // // (i < length) == 0 // (i < length) != 0 // (i < 100) == 0 // (i < 100) != 0 // // At this point, we have detected that op1.vn is (i < length) or (i < length + cns) or // (i < 100) and the op2.vn is 0. // // Now, let us check if we are == 0 (i.e., op1 assertion is false) or != 0 (op1 assertion // is true.), // // If we have an assertion of the form == 0 (i.e., equals false), then reverse relop. // The relop has to be reversed because we have: (i < length) is false which is the same // as (i >= length). if (curAssertion->assertionKind == Compiler::OAK_EQUAL) { cmpOper = GenTree::ReverseRelop(cmpOper); } // Bounds are inclusive, so add -1 for upper bound when "<". But make sure we won't overflow. if (cmpOper == GT_LT && !limit.AddConstant(-1)) { continue; } // Bounds are inclusive, so add +1 for lower bound when ">". But make sure we won't overflow. if (cmpOper == GT_GT && !limit.AddConstant(1)) { continue; } // Doesn't tighten the current bound. So skip. if (pRange->uLimit.IsConstant() && limit.vn != arrLenVN) { continue; } // Check if the incoming limit from assertions tightens the existing upper limit. if (pRange->uLimit.IsBinOpArray() && (pRange->uLimit.vn == arrLenVN)) { // We have checked the current range's (pRange's) upper limit is either of the form: // length + cns // and length == the bndsChkCandidate's arrLen // // We want to check if the incoming limit tightens the bound, and for that // we need to make sure that incoming limit is also on the same length (or // length + cns) and not some other length. if (limit.vn != arrLenVN) { JITDUMP("Array length VN did not match arrLen=" FMT_VN ", limit=" FMT_VN "\n", arrLenVN, limit.vn); continue; } int curCns = pRange->uLimit.cns; int limCns = (limit.IsBinOpArray()) ? limit.cns : 0; // Incoming limit doesn't tighten the existing upper limit. if (limCns >= curCns) { JITDUMP("Bound limit %d doesn't tighten current bound %d\n", limCns, curCns); continue; } } else { // Current range's upper bound is not "length + cns" and the // incoming limit is not on the same length as the bounds check candidate. // So we could skip this assertion. But in cases, of Dependent or Unknown // type of upper limit, the incoming assertion still tightens the upper // bound to a saner value. So do not skip the assertion. } // cmpOp (loop index i) cmpOper len +/- cns switch (cmpOper) { case GT_LT: pRange->uLimit = limit; break; case GT_GT: pRange->lLimit = limit; break; case GT_GE: pRange->lLimit = limit; break; case GT_LE: pRange->uLimit = limit; break; default: // All other 'cmpOper' kinds leave lLimit/uLimit unchanged break; } JITDUMP("The range after edge merging:"); JITDUMP(pRange->ToString(m_pCompiler->getAllocatorDebugOnly())); JITDUMP("\n"); } }
void CCameraInputHelper::UpdateCameraInput(Ang3 &deltaRotation, const float frameTimeClamped, const float frameTimeNormalised) { // Use new control scheme, // or, if we're just entering/leaving it then adjust camera/character orientations as appropriate. //--- Translate left stick into a deltaRotation.z (and a move direction) Vec3 vcStick=Vec3(m_pHeroInput->m_moveStickLR, m_pHeroInput->m_moveStickUD,0); // Stick vector in view space // -m_moveStickLR removes flicker, but inverses direction.. static Vec3 vcStickPrev=Vec3(0,1,0); float stickMag=vcStick.len(); if(stickMag>0.001f) vcStick*=1/stickMag; else vcStick=vcStickPrev; // should hold previous value/direction unless we're in transition. vcStickPrev=vcStick; Matrix33 camViewMtx = m_pHero->m_camViewMtxFinal; //in flight mode the actual camera matrix changes //the mtxFinal itself stays untouched, so that the camera can move back after the flight if(CCameraFlight::GetInstance()->IsCameraFlightActive()) { Vec3 vCamDir = CCameraFlight::GetInstance()->GetLookingDirection(); camViewMtx.SetRotationVDir(vCamDir, 0.0f); } const Matrix34& entityWorldTM = m_pHero->GetEntity()->GetWorldTM(); Vec3 vwEntPos = entityWorldTM.GetTranslation(); Vec3 vwDrawFrom = vwEntPos+Vec3(0,0,0.8f); Vec3 vwEntityFront = entityWorldTM.GetColumn1(); Vec3 vwEntityRight = entityWorldTM.GetColumn0(); Vec3 vCamRef = camViewMtx*Vec3(0,1,0); Vec3 vwStick = camViewMtx*vcStick; // Stick vector in world space Vec3 vwfStick = Vec3FlattenXY(vwStick); Vec3 vwfEntityFront=Vec3FlattenXY(vwEntityFront); Vec3 vwfEntityRight=Vec3FlattenXY(vwEntityRight); float dotRight=vwfStick.Dot(vwfEntityRight); float dotFront=vwfStick.Dot(vwfEntityFront); dotFront = clamp(dotFront,-1.0f,1.0f); bool enteredNavFromCombat = false; //(m_bNavCombatModeChanged && !bIsCombatMode); //--- Just moved into nav mode from combat if(enteredNavFromCombat) { // so set directions appropriately. float dotFront2=(vCamRef).Dot(Vec3(0,1,0)); float dotRight2=(camViewMtx*Vec3(1,0,0)).Dot(Vec3(0,1,0)); float yaw = 0.0f; dotFront2 = clamp(dotFront2,-1.0f,1.0f); if(dotRight2>=0) { yaw=-cry_acosf(dotFront2); } else { yaw=cry_acosf(dotFront2); } m_fYaw = yaw; } //this is the actual entity rotation (yaw movement) CCameraOverrides *pCamOverride = g_pGame->GetCameraManager()->GetCamOverrides(); int eCamOverrideMode = pCamOverride->GetCameraOverride(); //the ECO_LOWCOVER fading is a hack, causing problems when inputs are changed during the fade //in combat mode all inputs have to be passed through to synchronize the camera direction in other modes if((stickMag>0.01f && eCamOverrideMode != ECO_LOWCOVER)) { if(dotRight>=0) { deltaRotation.z=-cry_acosf(dotFront); } else { deltaRotation.z=cry_acosf(dotFront); } } else deltaRotation.z=0; float maxDeltaRot = 7.85f; // safety value //g_pGameCVars->cl_nav_SprintMaxTurnRate; Limit( maxDeltaRot, 0.f, gf_PI * 10.f ); // limit to 3600 degrees per second, i.e. 'pretty fast' maxDeltaRot *= frameTimeClamped; // In Nav mode movement is always in the characters forward direction. UpdatePitchYawDriver(stickMag, frameTimeNormalised); m_bNavCombatModeChanged=false; }
// Simple 2-poles resonant filter void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modifier) const { int cutoff = (int)pChn->nCutOff + (int)pChn->nCutSwing; int resonance = (int)(pChn->nResonance & 0x7F) + (int)pChn->nResSwing; Limit(cutoff, 0, 127); Limit(resonance, 0, 127); if(!m_playBehaviour[kMPTOldSwingBehaviour]) { pChn->nCutOff = (uint8)cutoff; pChn->nCutSwing = 0; pChn->nResonance = (uint8)resonance; pChn->nResSwing = 0; } // flt_modifier is in [-256, 256], so cutoff is in [0, 127 * 2] after this calculation. const int computedCutoff = cutoff * (flt_modifier + 256) / 256; // Filtering is only ever done in IT if either cutoff is not full or if resonance is set. if(m_playBehaviour[kITFilterBehaviour] && resonance == 0 && computedCutoff >= 254) { if(pChn->rowCommand.IsNote() && !pChn->rowCommand.IsPortamento() && !pChn->nMasterChn && m_SongFlags[SONG_FIRSTTICK]) { // Z7F next to a note disables the filter, however in other cases this should not happen. // Test cases: filter-reset.it, filter-reset-carry.it, filter-nna.it pChn->dwFlags.reset(CHN_FILTER); } return; } pChn->dwFlags.set(CHN_FILTER); // 2 * damping factor const float dmpfac = std::pow(10.0f, -resonance * ((24.0f / 128.0f) / 20.0f)); const float fc = CutOffToFrequency(cutoff, flt_modifier) * (2.0f * (float)M_PI); float d, e; if(m_playBehaviour[kITFilterBehaviour] && !m_SongFlags[SONG_EXFILTERRANGE]) { const float r = m_MixerSettings.gdwMixingFreq / fc; d = dmpfac * r + dmpfac - 1.0f; e = r * r; } else { const float r = fc / m_MixerSettings.gdwMixingFreq; d = (1.0f - 2.0f * dmpfac) * r; LimitMax(d, 2.0f); d = (2.0f * dmpfac - d) / r; e = 1.0f / (r * r); } float fg = 1.0f / (1.0f + d + e); float fb0 = (d + e + e) / (1 + d + e); float fb1 = -e / (1.0f + d + e); #if defined(MPT_INTMIXER) #define FILTER_CONVERT(x) Util::Round<mixsample_t>((x) * (1 << MIXING_FILTER_PRECISION)) #else #define FILTER_CONVERT(x) (x) #endif switch(pChn->nFilterMode) { case FLTMODE_HIGHPASS: pChn->nFilter_A0 = FILTER_CONVERT(1.0f - fg); pChn->nFilter_B0 = FILTER_CONVERT(fb0); pChn->nFilter_B1 = FILTER_CONVERT(fb1); #ifdef MPT_INTMIXER pChn->nFilter_HP = -1; #else pChn->nFilter_HP = 1.0f; #endif // MPT_INTMIXER break; default: pChn->nFilter_A0 = FILTER_CONVERT(fg); pChn->nFilter_B0 = FILTER_CONVERT(fb0); pChn->nFilter_B1 = FILTER_CONVERT(fb1); #ifdef MPT_INTMIXER if(pChn->nFilter_A0 == 0) pChn->nFilter_A0 = 1; // Prevent silence at low filter cutoff and very high sampling rate pChn->nFilter_HP = 0; #else pChn->nFilter_HP = 0; #endif // MPT_INTMIXER break; } #undef FILTER_CONVERT if (bReset) { pChn->nFilter_Y[0][0] = pChn->nFilter_Y[0][1] = 0; pChn->nFilter_Y[1][0] = pChn->nFilter_Y[1][1] = 0; } }
void Get(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t, Interval& valid) { Limit(v, owner, id, tabIndex, t); }
//------------------------------------------------------------------------ void CVehicleMovementHelicopter::ProcessActions(const float deltaTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); UpdateDamages(deltaTime); UpdateEngine(deltaTime); m_velDamp = 0.0f; m_playerControls.ProcessActions(deltaTime); Limit(m_forwardAction, -1.0f, 1.0f); Limit(m_strafeAction, -1.0f, 1.0f); m_actionYaw = 0.0f; Matrix33 tm(m_PhysPos.q); Ang3 angles = Ang3::GetAnglesXYZ(tm); Vec3 worldPos = m_PhysPos.pos; // +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; float pitchDeg = RAD2DEG(currentPitch); if(m_maxPitchAngleMov != 0.0f && pitchDeg >= (m_maxPitchAngleMov * 0.5f)) { float mult = pitchDeg / (m_maxPitchAngleMov); if(mult > 1.0f && m_desiredPitch < 0.0f) { m_desiredPitch *= 0.0f; m_actionPitch *= 0.0f; m_desiredPitch += 0.5f * mult; } else if(m_desiredPitch < 0.0f) { m_desiredPitch *= (1.0f - mult); m_desiredPitch += 0.05f; } } else if(m_maxPitchAngleMov != 0.0f && pitchDeg <= (-m_maxPitchAngleMov * 0.5f)) { float mult = abs(pitchDeg) / (m_maxPitchAngleMov); if(mult > 1.0f && m_desiredPitch > 0.0f) { m_desiredPitch *= 0.0f; m_actionPitch *= 0.0f; m_desiredPitch += 0.5f * mult; } else if(m_desiredPitch > 0.0f) { m_desiredPitch *= (1.0f - mult); m_desiredPitch -= 0.05f; } } if(m_pInvertPitchVar->GetIVal() == 0) m_desiredPitch *= -1.0f; Vec3 currentVel = m_PhysDyn.v; Vec3 currentVel2D = currentVel; currentVel2D.z = 0.0f; if(currentRoll >= DEG2RAD(m_maxRollAngle * 0.5f) && 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.5f) && 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); 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); if(!iszero(m_desiredPitch)) { m_actionPitch -= m_desiredPitch * m_pitchInputConst; Limit(m_actionPitch, -m_maxYawRate, m_maxYawRate); } m_actionRoll += m_pitchActionPerTilt * m_desiredRoll * (m_playerAcceleration + 1.0f); Limit(m_actionRoll, -10.0f, 10.0f); Limit(m_actionPitch, -10.0f, 10.0f); float relaxRollTolerance = 0.0f; if(!iszero(m_turnAction) || abs(m_PhysDyn.w.z) > DEG2RAD(10.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; float pitchComp = abs(currentPitch) / DEG2RAD(2.50f); if(pitchComp > 1.0f) roll *= pitchComp; 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; 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; } ProcessActionsLift(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))) CHANGED_NETWORK_STATE(m_pVehicle, eEA_GameClientDynamic); }
/** * Arcade drive implements single stick driving. * This function lets you directly provide joystick values from any source. * @param moveValue The value to use for fowards/backwards * @param rotateValue The value to use for the rotate right/left * @param squaredInputs If set, increases the sensitivity at low speeds */ void RobotDrive::ArcadeDrive(float moveValue, float rotateValue, bool squaredInputs) { static bool reported = false; if (!reported) { nUsageReporting::report(nUsageReporting::kResourceType_RobotDrive, GetNumMotors(), nUsageReporting::kRobotDrive_ArcadeStandard); reported = true; } // local variables to hold the computed PWM values for the motors float leftMotorOutput; float rightMotorOutput; moveValue = Limit(moveValue); rotateValue = Limit(rotateValue); if (squaredInputs) { // square the inputs (while preserving the sign) to increase fine control while permitting full power if (moveValue >= 0.0) { moveValue = (moveValue * moveValue); } else { moveValue = -(moveValue * moveValue); } if (rotateValue >= 0.0) { rotateValue = (rotateValue * rotateValue); } else { rotateValue = -(rotateValue * rotateValue); } } if (moveValue > 0.0) { if (rotateValue > 0.0) { leftMotorOutput = moveValue - rotateValue; rightMotorOutput = max(moveValue, rotateValue); } else { leftMotorOutput = max(moveValue, -rotateValue); rightMotorOutput = moveValue + rotateValue; } } else { if (rotateValue > 0.0) { leftMotorOutput = - max(-moveValue, rotateValue); rightMotorOutput = moveValue + rotateValue; } else { leftMotorOutput = moveValue - rotateValue; rightMotorOutput = - max(-moveValue, -rotateValue); } } SetLeftRightMotorOutputs(leftMotorOutput, rightMotorOutput); }
//=================================================================== // ProcessAI // This treats the helicopter as able to move in any horizontal direction // by tilting in any direction. Yaw control is thus secondary. Throttle // control is also secondary since it is adjusted to maintain or change // the height, and the amount needed depends on the tilt. //=================================================================== ////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementHelicopter::ProcessAI(const float deltaTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); // it's useless to progress further if the engine has yet to be turned on if(!m_isEnginePowered) return; m_movementAction.Clear(); ResetActions(); // Our current state const Vec3 worldPos = m_PhysPos.pos; const Matrix33 worldMat(m_PhysPos.q); const Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat); const Vec3 currentVel = m_PhysDyn.v; const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f); m_velDamp = 0.15f; // +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 desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength(); float powerfactor = desiredSpeed/m_maxSpeed; if(powerfactor < 1.0f) powerfactor = 1.0f; Limit(desiredTiltAngle, -(m_maxTiltAngle*powerfactor), (m_maxTiltAngle*powerfactor)); if(desiredTiltAngle > 0.0001f) { const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe(); const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis; float desiredPitch = desiredTiltAngle * desiredLocalTiltAxis.x; float desiredRoll = desiredTiltAngle * desiredLocalTiltAxis.y; m_actionPitch += m_pitchActionPerTilt * (desiredPitch - worldAngles.x); m_actionRoll += m_pitchActionPerTilt * (desiredRoll - worldAngles.y); } 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; m_actionYaw = (desiredDir - currentDir) * m_yawInputConst; m_actionYaw += m_yawInputDamping * (currentDir - m_lastDir) / deltaTime; m_lastDir = currentDir; Limit(m_actionPitch, -1.0f, 1.0f); Limit(m_actionRoll, -1.0f, 1.0f); Limit(m_actionYaw, -1.0f, 1.0f); Limit(m_hoveringPower, -1.0f, 1.0f); float currentHeight = worldPos.z; if(m_aiRequest.HasMoveTarget()) { m_hoveringPower = m_powerPID.Update(currentVel.z, desiredVel.z, -1.0f, 1.0f); m_liftAction = 0.0f; m_desiredHeight = currentHeight; } 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; } }
static bool StringToEnvelope(const std::string &s, InstrumentEnvelope &env, const CModSpecifications &specs) //---------------------------------------------------------------------------------------------------------- { uint32 susBegin = 0, susEnd = 0, loopBegin = 0, loopEnd = 0, bSus = 0, bLoop = 0, bCarry = 0, nPoints = 0, releaseNode = ENV_RELEASE_NODE_UNSET; size_t length = s.size(), pos = strlen(pszEnvHdr); if(length <= pos || mpt::CompareNoCaseAscii(s.c_str(), pszEnvHdr, pos - 2)) { return false; } sscanf(&s[pos], pszEnvFmt, &nPoints, &susBegin, &susEnd, &loopBegin, &loopEnd, &bSus, &bLoop, &bCarry); while (pos < length && s[pos] != '\r' && s[pos] != '\n') pos++; nPoints = MIN(nPoints, specs.envelopePointsMax); if (susEnd >= nPoints) susEnd = 0; if (susBegin > susEnd) susBegin = susEnd; if (loopEnd >= nPoints) loopEnd = 0; if (loopBegin > loopEnd) loopBegin = loopEnd; try { env.resize(nPoints); } MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e) { MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e); return false; } env.nSustainStart = susBegin; env.nSustainEnd = susEnd; env.nLoopStart = loopBegin; env.nLoopEnd = loopEnd; env.nReleaseNode = releaseNode; env.dwFlags.set(ENV_LOOP, bLoop != 0); env.dwFlags.set(ENV_SUSTAIN, bSus != 0); env.dwFlags.set(ENV_CARRY, bCarry != 0); env.dwFlags.set(ENV_ENABLED, nPoints > 0); int oldn = 0; for(auto &p : env) { while (pos < length && (s[pos] < '0' || s[pos] > '9')) pos++; if (pos >= length) break; int n1 = atoi(&s[pos]); while (pos < length && s[pos] != ',') pos++; while (pos < length && (s[pos] < '0' || s[pos] > '9')) pos++; if (pos >= length) break; int n2 = atoi(&s[pos]); if (n1 < oldn) n1 = oldn + 1; Limit(n2, ENVELOPE_MIN, ENVELOPE_MAX); p.tick = (uint16)n1; p.value = (uint8)n2; oldn = n1; while (pos < length && s[pos] != '\r' && s[pos] != '\n') pos++; if (pos >= length) break; } env.Sanitize(); // Read release node information. env.nReleaseNode = ENV_RELEASE_NODE_UNSET; if(pos < length) { uint8 r = static_cast<uint8>(atoi(&s[pos])); if(r == 0 || r >= nPoints || !specs.hasReleaseNode) r = ENV_RELEASE_NODE_UNSET; env.nReleaseNode = r; } return true; }
void CPlayerRotation::TargetAimAssistance(CWeapon* pWeapon, float& followH, float& followV, float& scale, float& _fZoomAmount, const Vec3 playerView[4]) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); CRY_ASSERT(m_player.IsClient()); followH = 0.0f; followV = 0.0f; scale = 1.0f; float bestScale = 1.0f; const Vec3 playerFwd = playerView[1]; const Vec3 playerRgt = playerView[0]; const Vec3 playerUp = playerView[2]; const Vec3 playerPos = playerView[3]; Vec3 follow_target_pos(ZERO); float follow_vote_leader = 0.0f; float snap_vote_leader = 0.0f; Vec3 follow_target_dir(ZERO); Vec3 snap_target_dir(ZERO); EntityId follow_target_id = 0; EntityId snap_target_id = 0; CGameRules * pGameRules = g_pGame->GetGameRules(); float distance_follow_threshold_near = max(0.0f, g_pGameCVars->aim_assistMinDistance); float distance_follow_threshold_far = max(20.0f, g_pGameCVars->aim_assistMaxDistance); int playerTeam = pGameRules->GetTeam(m_player.GetEntity()->GetId()); float cloakedPlayerMultiplier = g_pGameCVars->pl_aim_cloaked_multiplier; const bool multipleTeams = pGameRules->GetTeamCount() > 0; const float fFollowFalloffDist = g_pGameCVars->aim_assistFalloffDistance + FLT_EPSILON*g_pGameCVars->aim_assistFalloffDistance; const bool playerIsScoped = m_player.GetActorStats()->isScoped; float minTurnScale, fAimAssistStrength, fMaxDistMult; if(pWeapon) { const float fZoomAmount = pWeapon->GetZoomTransition(); _fZoomAmount = fZoomAmount; const float fStrength = g_pGameCVars->aim_assistStrength; const float fStrengthIronSight = playerIsScoped ? g_pGameCVars->aim_assistStrength_SniperScope : g_pGameCVars->aim_assistStrength_IronSight; const float fDiff = fStrengthIronSight - fStrength; fAimAssistStrength = fStrength + (fZoomAmount * fDiff); const float fMinTurn = g_pGameCVars->aim_assistMinTurnScale; const float fMinTurnIronSight = playerIsScoped ? g_pGameCVars->aim_assistMinTurnScale_SniperScope : g_pGameCVars->aim_assistMinTurnScale_IronSight; const float fMinTurnDiff = fMinTurnIronSight - fMinTurn; minTurnScale = fMinTurn + (fZoomAmount * fMinTurnDiff); const float fMaxAssistDist = g_pGameCVars->aim_assistMaxDistance; const float fMaxAssistDist_Iron = playerIsScoped ? g_pGameCVars->aim_assistMaxDistance_SniperScope : g_pGameCVars->aim_assistMaxDistance_IronSight; const float fMaxAssistDistDiff = (fMaxAssistDist_Iron - fMaxAssistDist) * fZoomAmount; fMaxDistMult = (fMaxAssistDist + fMaxAssistDistDiff) * __fres(fMaxAssistDist); } else { _fZoomAmount = 0.0f; fMaxDistMult = 1.0f; fAimAssistStrength = g_pGameCVars->aim_assistStrength; minTurnScale = g_pGameCVars->aim_assistMinTurnScale; } const float falloffStartDistance = g_pGameCVars->aim_assistSlowFalloffStartDistance; const float falloffPerMeter = 1.0f / (g_pGameCVars->aim_assistSlowDisableDistance - falloffStartDistance); const TAutoaimTargets& aaTargets = g_pGame->GetAutoAimManager().GetAutoAimTargets(); const int targetCount = aaTargets.size(); float fBestTargetDistance = FLT_MAX; #if DBG_AUTO_AIM SAuxGeomRenderFlags oldFlags = gEnv->pRenderer->GetIRenderAuxGeom()->GetRenderFlags(); SAuxGeomRenderFlags newFlags = e_Def3DPublicRenderflags; newFlags.SetAlphaBlendMode(e_AlphaBlended); newFlags.SetDepthTestFlag(e_DepthTestOff); newFlags.SetCullMode(e_CullModeNone); gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(newFlags); #endif for (int i = 0; i < targetCount; ++i) { const SAutoaimTarget& target = aaTargets[i]; CRY_ASSERT(target.entityId != m_player.GetEntityId()); //Skip friendly ai if(gEnv->bMultiplayer) { if(multipleTeams && (pGameRules->GetTeam(target.entityId) == playerTeam)) { continue; } } else { if (target.HasFlagSet(eAATF_AIHostile) == false) continue; distance_follow_threshold_far = fMaxDistMult * (target.HasFlagSet(eAATF_AIRadarTagged) ? g_pGameCVars->aim_assistMaxDistanceTagged : g_pGameCVars->aim_assistMaxDistance); } Vec3 targetPos = target.primaryAimPosition; Vec3 targetDistVec = (targetPos - playerPos); float distance = targetDistVec.GetLength(); if (distance <= 0.1f) continue; Vec3 dirToTarget = targetDistVec / distance; // fast reject everything behind player, too far away or too near from line of view // sort rest by angle to crosshair and distance from player float alignment = playerFwd * dirToTarget; if (alignment <= 0.0f) continue; if ((distance < distance_follow_threshold_near) || (distance > distance_follow_threshold_far)) continue; const int kAutoaimVisibilityLatency = 2; CPlayerVisTable::SVisibilityParams visParams(target.entityId); visParams.queryParams = eVQP_IgnoreGlass; if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(visParams, kAutoaimVisibilityLatency)) { // Since both player and target entities are ignored, and the ray still intersected something, there's something in the way. // Need to profile this and see if it's faster to do the below checks before doing the linetest. It's fairly expensive but // linetests generally are as well... - Richard continue; } #if DBG_AUTO_AIM const ColorB green(0,255,0,255); const ColorB darkgreen(0,155,0,225); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( playerPos, darkgreen, targetPos, green); #endif const float angleDot = dirToTarget.dot(-playerRgt); const float angle = (RAD2DEG(acos_tpl(angleDot)) - 90.f); const float absAngle = fabsf(angle); const float angleDotV = playerUp.dot(dirToTarget); const float angleToTargetV = (RAD2DEG(acos_tpl(angleDotV)) - 90.f); const float absAngleV = fabsf(angleToTargetV); const float slowModifiedDistance = distance * g_pGameCVars->aim_assistSlowDistanceModifier; const float radius_slow_threshold_inner = 0.5f; const float radius_slow_threshold_outer = g_pGameCVars->aim_assistSlowThresholdOuter; const float angle_slow_threshold_inner = RAD2DEG(atan_tpl(radius_slow_threshold_inner / slowModifiedDistance)); const float angle_slow_threshold_outer = RAD2DEG(atan_tpl(radius_slow_threshold_outer / slowModifiedDistance)); float angle_slow_fractionH = clamp_tpl((absAngle - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f); float angle_slow_fractionV = clamp_tpl((absAngleV - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f); float angle_slow_fraction = max(angle_slow_fractionH, angle_slow_fractionV); const float distance_follow_fraction = clamp_tpl((distance - fFollowFalloffDist) / (distance_follow_threshold_far - fFollowFalloffDist), 0.0f, 1.0f); const float radius_follow_threshold_inner = target.innerRadius; const float radius_follow_threshold_outer = target.outerRadius; const float radius_snap = target.HasFlagSet(eAATF_AIRadarTagged) ? target.snapRadiusTagged * g_pGameCVars->aim_assistSnapRadiusTaggedScale : target.snapRadius * g_pGameCVars->aim_assistSnapRadiusScale; const float angle_follow_threshold_inner = RAD2DEG(atan_tpl(radius_follow_threshold_inner / distance)); const float angle_follow_threshold_outer = RAD2DEG(atan_tpl(radius_follow_threshold_outer / distance)); const float angle_follow_fraction = clamp_tpl((absAngle - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f); const float angle_follow_fractionV = clamp_tpl((absAngleV - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f); const float worst_follow_fraction = (float)__fsel(angle_follow_fraction - angle_follow_fractionV, angle_follow_fraction, angle_follow_fractionV); float follow_fraction = ((1.0f - worst_follow_fraction) * (1.0f - distance_follow_fraction)); float follow_vote = follow_fraction; //clamp the lower bound of the distance_slow_modifier so it can't be lower than the angle slow fraction // which prevents close but off-centre targets slowing us too much const float distance_slow_modifier = clamp_tpl( 1.0f - ((distance - falloffStartDistance) * falloffPerMeter), angle_slow_fraction, 1.0f); const float fCombinedModifier = angle_slow_fraction * distance_slow_modifier; fBestTargetDistance = (float)__fsel(fCombinedModifier - bestScale, fBestTargetDistance, distance); bestScale = min(fCombinedModifier, bestScale); if (follow_vote > follow_vote_leader) { follow_vote_leader = follow_vote; //m_follow_target_id only gets set after the loop -> this won't get hit when a target is selected // as a follow target for the first time. This doesn't need to be in the loop. if ( m_follow_target_id == target.entityId) { const Vec3 follow_target_dir_local = m_follow_target_dir; Vec3 target_rgt = playerRgt; Vec3 target_up = target_rgt.cross(follow_target_dir_local); target_rgt = follow_target_dir_local.cross(target_up); target_rgt.Normalize(); target_up.Normalize(); float alignH = dirToTarget * -target_rgt; float alignV = dirToTarget.z - follow_target_dir_local.z; float angleH = min(fabsf(alignH * fAimAssistStrength), fabsf(angleDot)); float angleV = min(fabsf(alignV * fAimAssistStrength), fabsf(angleDotV)); followH = follow_fraction * (float)__fsel(angleDot, angleH, -angleH); followV = follow_fraction * (float)__fsel(angleDotV, angleV, -angleV); follow_vote_leader += 0.05f; // anti oscillation between different targets follow_target_pos = targetPos; } follow_target_id = target.entityId; snap_target_id = target.entityId; follow_target_dir = dirToTarget; snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target); } else if (!follow_target_id && (radius_snap > 0.0f)) { Lineseg lineSegment; lineSegment.start = playerPos; lineSegment.end = playerPos + (playerFwd * (distance + radius_snap)); Sphere sphere; sphere.center = targetPos; sphere.radius = radius_snap; Vec3 intersectionPoint; if (Intersect::Lineseg_SphereFirst(lineSegment, sphere, intersectionPoint)) { float t = 0.0f; const float snap_fraction = 1.0f - (Distance::Point_Lineseg(targetPos, lineSegment, t) * (float)__fres(radius_snap)); if (snap_fraction > snap_vote_leader) { snap_vote_leader = snap_fraction; snap_target_id = target.entityId; snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target); } } } } #if DBG_AUTO_AIM if ((!follow_target_pos.IsZeroFast()) && (g_pGameCVars->pl_targeting_debug != 0)) { float radius_inner = 0.30f; float radius_outer = 0.33f; ColorB colorInner(255,255,0,0x40); ColorB colorOuter(255,255,0,0x40); DrawDisc(follow_target_pos, follow_target_dir, radius_inner, radius_outer, colorInner, colorOuter); } gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(oldFlags); #endif m_follow_target_id = follow_target_id; m_follow_target_dir = follow_target_dir; //IMPORTANT: Apply the minimum-distance scaling of the slowdown _after_ calculating the slowdown for the best target // as we want to help the player aim at the nearest target, and modifying the slowdown multiplier prior to this // could result in a different target being selected const float fSlowDownProximityFadeInBand = (g_pGameCVars->aim_assistSlowStopFadeinDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) + FLT_EPSILON; float fSlowDownProximityScale = (fBestTargetDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) / fSlowDownProximityFadeInBand; Limit(fSlowDownProximityScale, 0.0f, 1.0f); float fInvBestScale = (1.0f - bestScale) * fSlowDownProximityScale; bestScale = 1.0f - fInvBestScale; scale = minTurnScale + ((1.0f - minTurnScale) * bestScale); UpdateCurrentSnapTarget(snap_target_id, snap_target_dir); }