void CPlayerRotation::ClampAngles( float minAngle, float maxAngle ) { //Cap up/down looking { const float currentViewPitch = GetLocalPitch(); const float newPitch = clamp_tpl(currentViewPitch + m_deltaAngles.x, minAngle, maxAngle); m_deltaAngles.x = newPitch - currentViewPitch; } //Further limit the view if necessary { const SViewLimitParams& viewLimits = m_player.m_params.viewLimits; const Vec3 limitDir = viewLimits.GetViewLimitDir(); if (limitDir.len2() < 0.1f) return; const float limitV = viewLimits.GetViewLimitRangeV(); const float limitH = viewLimits.GetViewLimitRangeH(); const float limitVUp = viewLimits.GetViewLimitRangeVUp(); const float limitVDown = viewLimits.GetViewLimitRangeVDown(); if ((limitH+limitV+fabsf(limitVUp)+fabsf(limitVDown)) > 0.0f) { //A matrix is built around the view limit, and then the player view angles are checked with it. //Later, if necessary the upVector could be made customizable. const Vec3 forward(limitDir); const Vec3 up(m_baseQuat.GetColumn2()); const Vec3 right((-(up % forward)).GetNormalized()); Matrix33 limitMtx; limitMtx.SetFromVectors(right,forward,right%forward); limitMtx.Invert(); const Vec3 localDir(limitMtx * m_viewQuat.GetColumn1()); Ang3 limit; if (limitV) { limit.x = asinf(localDir.z) + m_deltaAngles.x; const float deltaX(limitV - fabs(limit.x)); m_deltaAngles.x = m_deltaAngles.x + (float)__fsel(deltaX, 0.0f, deltaX * (float)__fsel(limit.x, 1.0f, -1.0f)); } if (limitVUp || limitVDown) { limit.x = asinf(localDir.z) + m_deltaAngles.x; const float deltaXUp(limitVUp - limit.x); float fNewDeltaX = m_deltaAngles.x; const float fDeltaXUpIncrement = (float)__fsel( deltaXUp, 0.0f, deltaXUp); fNewDeltaX = fNewDeltaX + (float)__fsel(-fabsf(limitVUp), 0.0f, fDeltaXUpIncrement); const float deltaXDown(limitVDown - limit.x); const float fDeltaXDownIncrement = (float)__fsel( deltaXDown, deltaXDown, 0.0f); fNewDeltaX = fNewDeltaX + (float)__fsel(-fabsf(limitVDown), 0.0f, fDeltaXDownIncrement); m_deltaAngles.x = fNewDeltaX; } if (limitH) { limit.z = atan2_tpl(-localDir.x,localDir.y) + m_deltaAngles.z; const float deltaZ(limitH - fabs(limit.z)); m_deltaAngles.z = m_deltaAngles.z + (float)__fsel(deltaZ, 0.0f, deltaZ * (float)__fsel(limit.z, 1.0f, -1.0f)); } } } }
void CPlayerRotation::ClampAngles() { { //cap up/down looking float minAngle,maxAngle; GetStanceAngleLimits(minAngle,maxAngle); float currentViewPitch=GetLocalPitch(); float newPitch = currentViewPitch + m_deltaAngles.x; if(newPitch < minAngle) newPitch = minAngle; else if(newPitch > maxAngle) newPitch = maxAngle; m_deltaAngles.x = newPitch - currentViewPitch; } { //further limit the view if necessary float limitV = m_params.vLimitRangeV; float limitH = m_params.vLimitRangeH; Vec3 limitDir = m_params.vLimitDir; float limitVUp = m_params.vLimitRangeVUp; float limitVDown = m_params.vLimitRangeVDown; if(m_player.m_stats.isFrozen.Value()) { float clampMin = g_pGameCVars->cl_frozenAngleMin; float clampMax = g_pGameCVars->cl_frozenAngleMax; float frozenLimit = DEG2RAD(clampMin + (clampMax-clampMin)*(1.f-m_player.GetFrozenAmount(true))); if(limitV == 0 || limitV>frozenLimit) limitV = frozenLimit; if(limitH == 0 || limitH>frozenLimit) limitH = frozenLimit; if(g_pGameCVars->cl_debugFreezeShake) { static float color[] = {1,1,1,1}; gEnv->pRenderer->Draw2dLabel(100,200,1.5,color,false,"limit: %f", RAD2DEG(frozenLimit)); } } if(m_player.m_stats.isOnLadder) { limitDir = -m_player.m_stats.ladderOrientation; limitH = DEG2RAD(40.0f); } if((limitH+limitV+limitVUp+limitVDown) && limitDir.len2()>0.1f) { //A matrix is built around the view limit, and then the player view angles are checked with it. //Later, if necessary the upVector could be made customizable. Vec3 forward(limitDir); Vec3 up(m_baseQuat.GetColumn2()); Vec3 right(-(up % forward)); right.Normalize(); Matrix33 limitMtx; limitMtx.SetFromVectors(right,forward,right%forward); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(m_player.GetEntity()->GetWorldPos(), ColorB(0,0,255,255), m_player.GetEntity()->GetWorldPos() + limitMtx.GetColumn(0), ColorB(0,0,255,255)); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(m_player.GetEntity()->GetWorldPos(), ColorB(0,255,0,255), m_player.GetEntity()->GetWorldPos() + limitMtx.GetColumn(1), ColorB(0,255,0,255)); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(m_player.GetEntity()->GetWorldPos(), ColorB(255,0,0,255), m_player.GetEntity()->GetWorldPos() + limitMtx.GetColumn(2), ColorB(255,0,0,255)); limitMtx.Invert(); Vec3 localDir(limitMtx * m_viewQuat.GetColumn1()); // Vec3 localDir(limitMtx * m_player.GetEntity()->GetWorldRotation().GetColumn1()); Ang3 limit; if(limitV) { limit.x = asinf(localDir.z) + m_deltaAngles.x; float deltaX(limitV - fabs(limit.x)); if(deltaX < 0.0f) m_deltaAngles.x += deltaX*(limit.x>0.0f?1.0f:-1.0f); } if(limitVUp || limitVDown) { limit.x = asinf(localDir.z) + m_deltaAngles.x; if(limit.x>=limitVUp && limitVUp!=0) { float deltaXUp(limitVUp - limit.x); m_deltaAngles.x += deltaXUp; } if(limit.x<=limitVDown && limitVDown!=0) { float deltaXDown(limitVDown - limit.x); m_deltaAngles.x += deltaXDown; } } if(limitH) { limit.z = cry_atan2f(-localDir.x,localDir.y) + m_deltaAngles.z; float deltaZ(limitH - fabs(limit.z)); if(deltaZ < 0.0f) m_deltaAngles.z += deltaZ*(limit.z>0.0f?1.0f:-1.0f); } } } }
/** * @brief Get all possible collisions with another line * @param aCompare Line to check * @param aOutput Output circle * @return If circle is found or not */ bool Line::GetCollisions(Line const &aCompare, Circle &aOutput) { Vector3 d = aCompare.position - position; float dist = d.length(); float longer = length >= aCompare.length ? length : aCompare.length; float shorter = length >= aCompare.length ? aCompare.length : length; print_line(*this); print_line(aCompare); // If they're in the exact same location that would be a problem if (position == aCompare.position) { // IS THIS THE SAME EXACT SPHERE?! if (length == aCompare.length) { aOutput.position = position; aOutput.radius = length; aOutput.up = Vector3(0, 1, 0); aOutput.right = Vector3(0, 0, 1); DebugLogPrint("Same exact sphere, gonna return false\n\n"); } else { DebugLogPrint("One sphere is inside of another, WAT\n"); DebugLogPrint("Therefore, cannot touch, gonna return false\n\n"); } print_circle(aOutput); DebugLogPrint("\n\n"); return false; } // > is an early out if (dist < length + aCompare.length && dist != longer - shorter) { // THE IDEA: Find one point, rotate about arbitrary axis between spheres // Reduce the problem to solving a circle Vector3 axis = d.normalize(); float xylength = sqrt(axis.x * axis.x + axis.y * axis.y); float xyzlength = axis.length(); // Don't want to divide by zero float templength = xylength > 0.0f ? xylength : 1.0f; // Our matrices // First, go to xz plane float xzvalues[3][3] = { { axis.x / templength, axis.y / templength, 0 }, { -axis.y / templength, axis.x / templength, 0 }, { 0, 0, 1 } }; // Then, only to z axis float zvalues[3][3] = { { axis.z / xyzlength, 0, -xylength / xyzlength }, { 0, 1, 0 }, { xylength / xyzlength, 0, axis.z / xyzlength } }; // Create identity matrix if we're already on the z plane if (xylength <= 0.0f) { xzvalues[0][0] = 1.0f; xzvalues[1][1] = 1.0f; xzvalues[1][0] = 0.0f; xzvalues[0][1] = 0.0f; } // Create our matrices and invert them Matrix33 xztrans(xzvalues); Matrix33 ztrans(zvalues); Matrix33 toZAxis = ztrans * xztrans; Matrix33 toZAxisInverse = toZAxis.Invert(); Vector3 comparePos = toZAxis * d; dist = comparePos.length(); // Circle collision function float z = ((dist * dist) - (aCompare.length * aCompare.length) + (length * length)) / (2.0f * dist); float y = sqrt((length * length) - (z * z)); // Create our circle aOutput.position = Vector3(0, 0, z); aOutput.up = Vector3(0, 1, 0); aOutput.right = Vector3(0, 0, 1); aOutput.radius = y; aOutput.position = toZAxisInverse * aOutput.position; aOutput.position += position; aOutput.up = toZAxisInverse * aOutput.up; aOutput.right = toZAxisInverse * aOutput.right; } else if (dist == length + aCompare.length) { // They barely touch, from the outside Vector3 largerPos = length >= aCompare.length ? position : aCompare.position; Vector3 smallerPos = length >= aCompare.length ? aCompare.position : position; float smallerLen = length >= aCompare.length ? aCompare.length : length; d = smallerPos - largerPos; DebugLogPrint("The radii barely touch, will still return true, but radius is zero\n"); aOutput.position = smallerPos - (d.normalize() * smallerLen); aOutput.radius = 0; aOutput.up = Vector3(0, 1, 0); aOutput.right = Vector3(0, 0, 1); } else if (dist == longer - shorter) { // They barely touch, from the inside Vector3 largerPos = length >= aCompare.length ? position : aCompare.position; Vector3 smallerPos = length >= aCompare.length ? aCompare.position : position; float smallerLen = length >= aCompare.length ? aCompare.length : length; d = smallerPos - largerPos; DebugLogPrint("The radii barely touch, will still return true, but radius is zero\n"); aOutput.position = smallerPos + (d.normalize() * smallerLen); aOutput.radius = 0; aOutput.up = Vector3(0, 1, 0); aOutput.right = Vector3(0, 0, 1); } else { DebugLogPrint("These LineSegments can never touch. Returning false.\n\n"); return false; } print_circle(aOutput); DebugLogPrint("\n\n"); return true; }