internal void Update(RPMVesselComputer comp) { float value; if (enablingVariable != null) { if (!enablingVariable.IsInRange(comp)) { return; } } if (variable.Get(out value, comp)) { if (useLog10) { value = JUtil.PseudoLog10(value); } float xOffset = JUtil.DualLerp(textureLimit, scale, value); MeshFilter meshFilter = barObject.GetComponent <MeshFilter>(); meshFilter.mesh.uv = new[] { new Vector2(xOffset - textureSize, 0.0f), new Vector2(xOffset + textureSize, 0.0f), new Vector2(xOffset - textureSize, 1.0f), new Vector2(xOffset + textureSize, 1.0f) }; JUtil.ShowHide(true, barObject); } }
public void Draw(Rect screenRect, double time) { double mintime = time - horizontalSpan; if (floatingMin && points.Count > 0) { verticalSpan.x = (float)points[0].y; foreach (Vector2d dataPoint in points) { verticalSpan.x = (float)Math.Min(dataPoint.y, verticalSpan.x); } } if (floatingMax && points.Count > 0) { verticalSpan.y = (float)points[0].y; foreach (Vector2d dataPoint in points) { verticalSpan.y = (float)Math.Max(dataPoint.y, verticalSpan.y); } } var actualXY = new List <Vector2>(); foreach (Vector2d dataPoint in points) { if (dataPoint.x > mintime) { actualXY.Add(new Vector2( (float)JUtil.DualLerp(screenRect.xMin, screenRect.xMax, mintime, time, dataPoint.x), (float)JUtil.DualLerp(screenRect.yMin, screenRect.yMax, verticalSpan.x, verticalSpan.y, dataPoint.y) )); } } DrawVector(actualXY, lineColor); }
internal void Update() { if (enablingVariable != null) { if (!enablingVariable.IsInRange()) { return; } } float value = variable.AsFloat(); if (useLog10) { value = JUtil.PseudoLog10(value); } float yOffset = JUtil.DualLerp(textureLimit, scale, value); MeshFilter meshFilter = barObject.GetComponent <MeshFilter>(); meshFilter.mesh.uv = new[] { new Vector2(0.0f, yOffset - textureSize), new Vector2(1.0f, yOffset - textureSize), new Vector2(0.0f, yOffset + textureSize), new Vector2(1.0f, yOffset + textureSize) }; JUtil.ShowHide(true, barObject); }
/// <summary> /// Update the compass / heading bar /// </summary> private void UpdateHeading(Quaternion rotationVesselSurface, RPMVesselComputer comp) { float heading = rotationVesselSurface.eulerAngles.y / 360.0f; MeshFilter meshFilter = headingMesh.GetComponent <MeshFilter>(); meshFilter.mesh.uv = new[] { new Vector2(heading - headingBarTextureWidth, 0.0f), new Vector2(heading + headingBarTextureWidth, 0.0f), new Vector2(heading - headingBarTextureWidth, 1.0f), new Vector2(heading + headingBarTextureWidth, 1.0f) }; if (progradeHeadingIcon != null) { float slipAngle = comp.Sideslip; float slipTC = JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y + slipAngle); float slipIconX = JUtil.DualLerp(progradeHeadingIconOrigin - 0.5f * headingBarPosition.z, progradeHeadingIconOrigin + 0.5f * headingBarPosition.z, heading - headingBarTextureWidth, heading + headingBarTextureWidth, slipTC); Vector3 position = progradeHeadingIcon.transform.position; position.x = slipIconX; progradeHeadingIcon.transform.position = position; JUtil.ShowHide(true, progradeHeadingIcon); } }
public double Evaluate(RPMVesselComputer comp, PersistenceAccessor persistence) { float result = comp.ProcessVariable(sourceVariable, persistence).MassageToFloat(); Vector2 sourceRange; if (!string.IsNullOrEmpty(sourceMinStr)) { sourceRange.x = comp.ProcessVariable(sourceMinStr, persistence).MassageToFloat(); } else { sourceRange.x = sourceMin; } if (!string.IsNullOrEmpty(sourceMaxStr)) { sourceRange.y = comp.ProcessVariable(sourceMaxStr, persistence).MassageToFloat(); } else { sourceRange.y = sourceMax; } return(JUtil.DualLerp(mappedRange, sourceRange, result)); }
// This is honestly very badly written code, probably the worst of what I have in this project. // Much of it dictated by the fact that I barely, if at all, understand what am I doing in vector mathematics, // the rest is because the problem is all built out of special cases. // Sorry. :) public bool RenderPFD(RenderTexture screen, float aspect) { if (screen == null || !startupComplete || HighLogic.LoadedSceneIsEditor) { return(false); } // Analysis disable once CompareOfFloatsByEqualityOperator if (aspect != cameraAspect) { cameraAspect = aspect; ballCamera.aspect = cameraAspect; } GL.Clear(true, true, backgroundColorValue); ballCamera.targetTexture = screen; Vector3d coM = vessel.findWorldCenterOfMass(); Vector3d up = (coM - vessel.mainBody.position).normalized; Vector3d velocityVesselOrbit = vessel.orbit.GetVel(); Vector3d velocityVesselOrbitUnit = velocityVesselOrbit.normalized; Vector3d velocityVesselSurface = velocityVesselOrbit - vessel.mainBody.getRFrmVel(coM); Vector3d velocityVesselSurfaceUnit = velocityVesselSurface.normalized; Vector3d radialPlus = Vector3d.Exclude(velocityVesselOrbit, up).normalized; Vector3d normalPlus = -Vector3d.Cross(radialPlus, velocityVesselOrbitUnit); //Vector3d targetDirection = -FlightGlobals.fetch.vesselTargetDirection.normalized; Vector3d targetDirection = FlightGlobals.ship_tgtVelocity.normalized; navBall.transform.rotation = MirrorX(stockNavBall.navBall.rotation); if (heading != null) { Vector3d north = Vector3d.Exclude(up, (vessel.mainBody.position + (Vector3d)vessel.mainBody.transform.up * vessel.mainBody.Radius) - coM).normalized; Quaternion rotationSurface = Quaternion.LookRotation(north, up); Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.GetTransform().rotation) * rotationSurface); heading.renderer.material.SetTextureOffset("_MainTex", new Vector2(JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y) - headingSpan / 2f, 0)); } Quaternion gymbal = stockNavBall.attitudeGymbal; switch (FlightUIController.speedDisplayMode) { case FlightUIController.SpeedDisplayModes.Surface: MoveMarker(markerPrograde, velocityVesselSurfaceUnit, progradeColorValue, gymbal); MoveMarker(markerRetrograde, -velocityVesselSurfaceUnit, progradeColorValue, gymbal); break; case FlightUIController.SpeedDisplayModes.Target: MoveMarker(markerPrograde, targetDirection, progradeColorValue, gymbal); MoveMarker(markerRetrograde, -targetDirection, progradeColorValue, gymbal); break; case FlightUIController.SpeedDisplayModes.Orbit: MoveMarker(markerPrograde, velocityVesselOrbitUnit, progradeColorValue, gymbal); MoveMarker(markerRetrograde, -velocityVesselOrbitUnit, progradeColorValue, gymbal); break; } MoveMarker(markerNormal, normalPlus, normalColorValue, gymbal); MoveMarker(markerNormalMinus, -normalPlus, normalColorValue, gymbal); MoveMarker(markerRadial, radialPlus, radialColorValue, gymbal); MoveMarker(markerRadialMinus, -radialPlus, radialColorValue, gymbal); if (vessel.patchedConicSolver != null && vessel.patchedConicSolver.maneuverNodes.Count > 0) { Vector3d burnVector = vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(vessel.orbit); MoveMarker(markerManeuver, burnVector.normalized, maneuverColorValue, gymbal); MoveMarker(markerManeuverMinus, -burnVector.normalized, maneuverColorValue, gymbal); ShowHide(true, markerManeuver, markerManeuverMinus); } ITargetable target = FlightGlobals.fetch.VesselTarget; if (target != null) { Vector3 targetSeparation = (vessel.GetTransform().position - target.GetTransform().position).normalized; MoveMarker(markerTarget, targetSeparation, targetColorValue, gymbal); MoveMarker(markerTargetMinus, -targetSeparation, targetColorValue, gymbal); var targetPort = target as ModuleDockingNode; if (targetPort != null) { // Thanks to Michael Enßlin Transform targetTransform = targetPort.transform; Transform selfTransform = vessel.ReferenceTransform; Vector3 targetOrientationVector = -targetTransform.up.normalized; Vector3 v1 = Vector3.Cross(selfTransform.up, targetTransform.forward); Vector3 v2 = Vector3.Cross(selfTransform.up, selfTransform.forward); float angle = Vector3.Angle(v1, v2); if (Vector3.Dot(selfTransform.up, Vector3.Cross(v1, v2)) < 0) { angle = -angle; } MoveMarker(markerDockingAlignment, targetOrientationVector, dockingColorValue, gymbal); markerDockingAlignment.transform.Rotate(Vector3.up, -angle); ShowHide(true, markerDockingAlignment); } ShowHide(true, markerTarget, markerTargetMinus); } // This dirty hack reduces the chance that the ball might get affected by internal cabin lighting. int backupQuality = QualitySettings.pixelLightCount; QualitySettings.pixelLightCount = 0; ShowHide(true, cameraBody, navBall, overlay, heading, markerPrograde, markerRetrograde, markerNormal, markerNormalMinus, markerRadial, markerRadialMinus); ballCamera.Render(); QualitySettings.pixelLightCount = backupQuality; ShowHide(false, cameraBody, navBall, overlay, heading, markerPrograde, markerRetrograde, markerManeuver, markerManeuverMinus, markerTarget, markerTargetMinus, markerNormal, markerNormalMinus, markerRadial, markerRadialMinus, markerDockingAlignment); return(true); }
private void UpdateOdometer() { double thisUpdate = Planetarium.GetUniversalTime(); float dT = (float)(thisUpdate - lastUpdate) * odometerRotationScalar; RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); float value; if (!string.IsNullOrEmpty(perPodPersistenceName)) { bool state = rpmComp.GetBool(perPodPersistenceName, false); value = comp.ProcessVariable((state) ? altVariable : variable).MassageToFloat(); } else { value = comp.ProcessVariable(variable).MassageToFloat(); } // Make sure the value isn't going to be a problem. if (float.IsNaN(value)) { value = 0.0f; } if (value < 0.0f) { signGoalCoord = 0.625f; } else if (value > 0.0f) { signGoalCoord = 0.875f; } else { signGoalCoord = 0.75f; } signCurrentCoord = JUtil.DualLerp(signCurrentCoord, signGoalCoord, 0.0f, 1.0f, dT); value = Mathf.Abs(value); if (oMode == OdometerMode.SI) { float leadingDigitExponent; if (value < 0.001f) { leadingDigitExponent = -3.0f; } else { leadingDigitExponent = Mathf.Floor(Mathf.Log10(value)); } // siExponent is the location relative to the original decimal of // the SI prefix. Is is always the greatest multiple-of-3 less // than the leadingDigitExponent. int siIndex = (int)Mathf.Floor(leadingDigitExponent / 3.0f); if (siIndex > 3) { siIndex = 3; } int siExponent = siIndex * 3; prefixGoalCoord = (float)(siIndex + 1) * 0.125f; prefixCurrentCoord = JUtil.DualLerp(prefixCurrentCoord, prefixGoalCoord, 0.0f, 1.0f, dT); float scaledValue = value / Mathf.Pow(10.0f, (float)(siExponent - 3)); int intValue = (int)(scaledValue); for (int i = 5; i >= 0; --i) { float thisCoord = (float)(intValue % 10) / 10.0f; if (i == 5) { // So we can display fractional values: // However, we also quantize it to make it easier to // read during the transition from 9 to 0. thisCoord = Mathf.Floor((scaledValue % 10.0f) * 2.0f) / 20.0f; } intValue = intValue / 10; goalCoordinate[i] = thisCoord; } } else if (oMode == OdometerMode.TIME_HHHMMSS) { // Clamp the value value = Mathf.Min(value, 59.0f + 59.0f * 60.0f + 999.0f * 60.0f * 24.0f); // seconds float thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f; goalCoordinate[6] = thisCoord; int intValue = (int)(value) / 10; // tens of seconds thisCoord = (float)(intValue % 6) / 10.0f; goalCoordinate[5] = thisCoord; intValue /= 6; // minutes thisCoord = (float)(intValue % 10) / 10.0f; goalCoordinate[4] = thisCoord; intValue /= 10; // tens of minutes thisCoord = (float)(intValue % 6) / 10.0f; goalCoordinate[3] = thisCoord; intValue /= 6; for (int i = 2; i >= 0; --i) { thisCoord = (float)(intValue % 10) / 10.0f; intValue = intValue / 10; goalCoordinate[i] = thisCoord; } } else { int intValue = (int)(value); for (int i = 7; i >= 0; --i) { float thisCoord = (float)(intValue % 10) / 10.0f; if (i == 7) { thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f; } intValue = intValue / 10; goalCoordinate[i] = thisCoord; } } // Update interpolants for (int i = 0; i < 8; ++i) { if (currentCoordinate[i] != goalCoordinate[i]) { float startingPoint; float endingPoint; if (Mathf.Abs(currentCoordinate[i] - goalCoordinate[i]) <= 0.5f) { startingPoint = currentCoordinate[i]; endingPoint = goalCoordinate[i]; } else if (goalCoordinate[i] < currentCoordinate[i]) { startingPoint = currentCoordinate[i]; endingPoint = goalCoordinate[i] + 1.0f; } else { startingPoint = currentCoordinate[i] + 1.0f; endingPoint = goalCoordinate[i]; } // This lerp causes a rotation that starts quickly but // slows down close to the goal. It actually looks // pretty good for typical incrementing counts, while the // rapid spinning of small values is chaotic enough that // you can't really tell what's going on, anyway. float goal = JUtil.DualLerp(startingPoint, endingPoint, 0.0f, 1.0f, dT); if (goal > 1.0f) { goal -= 1.0f; } currentCoordinate[i] = goal; } } lastUpdate = thisUpdate; }
public void Update(RPMVesselComputer comp, PersistenceAccessor persistence) { var scaleResults = new float[3]; for (int i = 0; i < 3; i++) { if (!scaleEnds[i].Get(out scaleResults[i], comp, persistence)) { return; } } float scaledValue = Mathf.InverseLerp(scaleResults[0], scaleResults[1], scaleResults[2]); if (thresholdMode) { if (scaledValue >= threshold.x && scaledValue <= threshold.y) { if (flashingDelay > 0) { if (lastStateChange < Planetarium.GetUniversalTime() - flashingDelay) { if (currentState) { TurnOff(); } else { TurnOn(); } } } else { TurnOn(); } if (audioOutput != null && !alarmActive) { audioOutput.audio.Play(); alarmActive = true; } } else { TurnOff(); if (audioOutput != null && alarmActive) { if (!alarmMustPlayOnce) { audioOutput.audio.Stop(); } alarmActive = false; } } // Resetting the audio volume in case it was muted while the ship was out of IVA. if (alarmActive && audioOutput != null) { audioOutput.audio.volume = alarmSoundVolume * GameSettings.SHIP_VOLUME; } } else { switch (mode) { case Mode.Rotation: Quaternion newRotation = longPath ? Quaternion.Euler(Vector3.Lerp(reverse ? vectorEnd : vectorStart, reverse ? vectorStart : vectorEnd, scaledValue)) : Quaternion.Slerp(reverse ? rotationEnd : rotationStart, reverse ? rotationStart : rotationEnd, scaledValue); controlledTransform.localRotation = initialRotation * newRotation; break; case Mode.Translation: controlledTransform.localPosition = initialPosition + Vector3.Lerp(reverse ? vectorEnd : vectorStart, reverse ? vectorStart : vectorEnd, scaledValue); break; case Mode.Scale: controlledTransform.localScale = initialScale + Vector3.Lerp(reverse ? vectorEnd : vectorStart, reverse ? vectorStart : vectorEnd, scaledValue); break; case Mode.Color: colorShiftRenderer.material.SetColor(colorName, Color.Lerp(reverse ? activeColor : passiveColor, reverse ? passiveColor : activeColor, scaledValue)); break; case Mode.TextureShift: foreach (string token in textureLayer.Split(',')) { affectedMaterial.SetTextureOffset(token.Trim(), Vector2.Lerp(reverse ? textureShiftEnd : textureShiftStart, reverse ? textureShiftStart : textureShiftEnd, scaledValue)); } break; case Mode.TextureScale: foreach (string token in textureLayer.Split(',')) { affectedMaterial.SetTextureScale(token.Trim(), Vector2.Lerp(reverse ? textureScaleEnd : textureScaleStart, reverse ? textureScaleStart : textureScaleEnd, scaledValue)); } break; case Mode.LoopingAnimation: // MOARdV TODO: Define what this actually does case Mode.Animation: float lerp = JUtil.DualLerp(reverse ? 1f : 0f, reverse ? 0f : 1f, scaleResults[0], scaleResults[1], scaleResults[2]); if (float.IsNaN(lerp) || float.IsInfinity(lerp)) { lerp = reverse ? 1f : 0f; } onAnim[animationName].normalizedTime = lerp; break; } } }
/// <summary> /// Update the ladder's texture UVs so it's drawn correctly /// </summary> private void UpdateLadder(Quaternion rotationVesselSurface, RPMVesselComputer comp) { float pitch = 90.0f - Vector3.Angle(comp.Forward, comp.Up); float ladderMidpointCoord; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; ladderMidpointCoord = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, pitch); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; ladderMidpointCoord = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, pitch); } // MOARdV TODO: These can be done without manually editing the // mesh filter. I need to look up the game object texture stuff. MeshFilter meshFilter = ladderMesh.GetComponent <MeshFilter>(); meshFilter.mesh.uv = new[] { new Vector2(0.5f - horizonTextureSize.x, ladderMidpointCoord - horizonTextureSize.y), new Vector2(0.5f + horizonTextureSize.x, ladderMidpointCoord - horizonTextureSize.y), new Vector2(0.5f - horizonTextureSize.x, ladderMidpointCoord + horizonTextureSize.y), new Vector2(0.5f + horizonTextureSize.x, ladderMidpointCoord + horizonTextureSize.y) }; float roll = rotationVesselSurface.eulerAngles.z; ladderMesh.transform.Rotate(new Vector3(0.0f, 0.0f, 1.0f), lastRoll - roll); lastRoll = roll; if (progradeLadderIcon != null) { float AoA = comp.AbsoluteAoA; AoA = (float)JUtil.ClampDegrees180(AoA); if (float.IsNaN(AoA)) { AoA = 0.0f; } float AoATC; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; AoATC = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, AoA); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; AoATC = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, AoA); } float Ypos = JUtil.DualLerp( -horizonSize.y * 0.5f, horizonSize.y * 0.5f, ladderMidpointCoord - horizonTextureSize.y, ladderMidpointCoord + horizonTextureSize.y, AoATC); Vector3 position = progradeLadderIcon.transform.position; position.x = Ypos * Mathf.Sin(roll * Mathf.Deg2Rad); position.y = Ypos * Mathf.Cos(roll * Mathf.Deg2Rad); progradeLadderIcon.transform.position = position; JUtil.ShowHide(true, progradeLadderIcon); } }
// BAR -- Bar pseudo-formatter that produces a horizontal bar // Nice for creating pseudo-bar charts. // BAR[<bar character>[<empty character>]],<total length>[,<minimum>[,<maximum>]] // Examples: // BAR,10,10000,200000 // BAR= ,10,0,200 // BAR~,10,0,200 // BAR,10 private static string BARFormat(string format, double value) { char fullChar = '='; char emptyChar = ' '; string trailerChar = string.Empty; double maximum = 1; double minimum = 0; string[] tokens = format.Split(','); if (tokens.Length < 2) { return(value.ToString(format)); } if (tokens[0].Length == formatPrefixBAR.Length + 3) { trailerChar = new string(tokens[0][formatPrefixBAR.Length + 2], 1); } if (tokens[0].Length == formatPrefixBAR.Length + 2) { emptyChar = tokens[0][formatPrefixBAR.Length + 1]; } if (tokens[0].Length >= formatPrefixBAR.Length + 1) { fullChar = tokens[0][formatPrefixBAR.Length]; } int outputLength = 0; bool reverse = false; try { if (tokens.Length > 1) { outputLength = int.Parse(tokens[1]); if (outputLength < 0) { outputLength = Math.Abs(outputLength); reverse = true; } } if (tokens.Length > 2) { minimum = double.Parse(tokens[2]); } if (tokens.Length > 3) { maximum = double.Parse(tokens[3]); } } catch { return(value.ToString(format)); } if (double.IsNaN(value)) { value = 0.0; } if (double.IsInfinity(value)) { value = maximum; } int filledLength = (int)JUtil.DualLerp(0, outputLength, minimum, maximum, value); string filledPart = string.Empty; if (!string.IsNullOrEmpty(trailerChar)) { if (filledLength > 0) { if (filledLength == 1) { filledPart = trailerChar; } else { filledPart = string.Empty.PadRight(filledLength - 1, fullChar); filledPart = reverse ? trailerChar + filledPart : filledPart + trailerChar; } } } else { filledPart = string.Empty.PadRight(filledLength, fullChar); } return(reverse ? filledPart.PadLeft(outputLength, emptyChar) : filledPart.PadRight(outputLength, emptyChar)); }
public bool RenderHUD(RenderTexture screen, float cameraAspect) { if (screen == null || !startupComplete || HighLogic.LoadedSceneIsEditor) { return(false); } // Clear the background, if configured. GL.Clear(true, true, backgroundColorValue); // Configure the camera, if configured. // MOARdV: Might be worthwhile to refactor the flying camera so // it is created in Start (like new FlyingCamera(part, cameraTransform)), // and pass the screen, FoV, and aspect ratio (or just screen and // FoV) as Render parameters, so there's no need to test if the // camera's been created every render call. if (cameraObject == null && !string.IsNullOrEmpty(cameraTransform)) { cameraObject = new FlyingCamera(part, screen, cameraAspect); cameraObject.PointCamera(cameraTransform, hudFov); } // Draw the camera's view, if configured. if (cameraObject != null) { cameraObject.Render(); } // Configure the matrix so that the origin is the center of the screen. GL.PushMatrix(); // Draw the HUD ladder // MOARdV note, 2014/03/19: swapping the y values, to invert the // coordinates so the prograde icon is right-side up. GL.LoadPixelMatrix(-horizonSize.x * 0.5f, horizonSize.x * 0.5f, horizonSize.y * 0.5f, -horizonSize.y * 0.5f); GL.Viewport(new Rect((screen.width - horizonSize.x) * 0.5f, (screen.height - horizonSize.y) * 0.5f, horizonSize.x, horizonSize.y)); Vector3 coM = vessel.findWorldCenterOfMass(); Vector3 up = (coM - vessel.mainBody.position).normalized; Vector3 forward = vessel.GetTransform().up; Vector3 right = vessel.GetTransform().right; Vector3 top = Vector3.Cross(right, forward); Vector3 north = Vector3.Exclude(up, (vessel.mainBody.position + (Vector3d)vessel.mainBody.transform.up * vessel.mainBody.Radius) - coM).normalized; Vector3d velocityVesselSurface = vessel.orbit.GetVel() - vessel.mainBody.getRFrmVel(coM); Vector3 velocityVesselSurfaceUnit = velocityVesselSurface.normalized; if (ladderMaterial) { // Figure out the texture coordinate scaling for the ladder. float ladderTextureOffset = horizonTextureSize.y / ladderMaterial.mainTexture.height; float cosUp = Vector3.Dot(forward, up); float cosRoll = Vector3.Dot(top, up); float sinRoll = Vector3.Dot(right, up); var normalizedRoll = new Vector2(cosRoll, sinRoll); normalizedRoll.Normalize(); if (normalizedRoll.magnitude < 0.99f) { // If we're hitting +/- 90 nearly perfectly, the sin and cos will // be too far out of whack to normalize. Arbitrarily pick // a roll of 0.0. normalizedRoll.x = 1.0f; normalizedRoll.y = 0.0f; } cosRoll = normalizedRoll.x; sinRoll = normalizedRoll.y; // Mihara: I'm pretty sure this was negative of what it should actually be, at least according to my mockup. float pitch = -(Mathf.Asin(cosUp) * Mathf.Rad2Deg); float ladderMidpointCoord; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; ladderMidpointCoord = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, pitch); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; ladderMidpointCoord = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, pitch); } ladderMaterial.SetPass(0); GL.Begin(GL.QUADS); // transform -x -y GL.TexCoord2(0.5f + horizonTextureSize.x, ladderMidpointCoord - ladderTextureOffset); GL.Vertex3(cosRoll * horizonSize.x + sinRoll * horizonSize.y, -sinRoll * horizonSize.x + cosRoll * horizonSize.y, 0.0f); // transform +x -y GL.TexCoord2(0.5f - horizonTextureSize.x, ladderMidpointCoord - ladderTextureOffset); GL.Vertex3(-cosRoll * horizonSize.x + sinRoll * horizonSize.y, sinRoll * horizonSize.x + cosRoll * horizonSize.y, 0.0f); // transform +x +y GL.TexCoord2(0.5f - horizonTextureSize.x, ladderMidpointCoord + ladderTextureOffset); GL.Vertex3(-cosRoll * horizonSize.x - sinRoll * horizonSize.y, sinRoll * horizonSize.x - cosRoll * horizonSize.y, 0.0f); // transform -x +y GL.TexCoord2(0.5f + horizonTextureSize.x, ladderMidpointCoord + ladderTextureOffset); GL.Vertex3(cosRoll * horizonSize.x - sinRoll * horizonSize.y, -sinRoll * horizonSize.x - cosRoll * horizonSize.y, 0.0f); GL.End(); float AoA = velocityVesselSurfaceUnit.AngleInPlane(right, forward); float AoATC; if (use360horizon) { // Straight up is texture coord 0.75; // Straight down is TC 0.25; AoATC = JUtil.DualLerp(0.25f, 0.75f, -90f, 90f, pitch + AoA); } else { // Straight up is texture coord 1.0; // Straight down is TC 0.0; AoATC = JUtil.DualLerp(0.0f, 1.0f, -90f, 90f, pitch + AoA); } float Ypos = JUtil.DualLerp( -horizonSize.y, horizonSize.y, ladderMidpointCoord - ladderTextureOffset, ladderMidpointCoord + ladderTextureOffset, AoATC); // Placing the icon on the (0, Ypos) location, so simplify the transform. DrawIcon(-sinRoll * Ypos, -cosRoll * Ypos, GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE), progradeColorValue); } // Draw the rest of the HUD stuff (0,0) is the top left corner of the screen. GL.LoadPixelMatrix(0, screen.width, screen.height, 0); GL.Viewport(new Rect(0, 0, screen.width, screen.height)); if (headingMaterial != null) { Quaternion rotationSurface = Quaternion.LookRotation(north, up); Quaternion rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.GetTransform().rotation) * rotationSurface); float headingTexture = JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y); float headingTextureOffset = (headingBarWidth / headingMaterial.mainTexture.width) / 2; headingMaterial.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(headingTexture - headingTextureOffset, 1.0f); GL.Vertex3(headingBarPosition.x, headingBarPosition.y, 0.0f); GL.TexCoord2(headingTexture + headingTextureOffset, 1.0f); GL.Vertex3(headingBarPosition.x + headingBarPosition.z, headingBarPosition.y, 0.0f); GL.TexCoord2(headingTexture + headingTextureOffset, 0.0f); GL.Vertex3(headingBarPosition.x + headingBarPosition.z, headingBarPosition.y + headingBarPosition.w, 0.0f); GL.TexCoord2(headingTexture - headingTextureOffset, 0.0f); GL.Vertex3(headingBarPosition.x, headingBarPosition.y + headingBarPosition.w, 0.0f); GL.End(); if (showHeadingBarPrograde) { float slipAngle = velocityVesselSurfaceUnit.AngleInPlane(up, forward); float slipTC = JUtil.DualLerp(0f, 1f, 0f, 360f, rotationVesselSurface.eulerAngles.y + slipAngle); float slipIconX = JUtil.DualLerp(headingBarPosition.x, headingBarPosition.x + headingBarPosition.z, headingTexture - headingTextureOffset, headingTexture + headingTextureOffset, slipTC); DrawIcon(slipIconX, headingBarPosition.y + headingBarPosition.w * 0.5f, GizmoIcons.GetIconLocation(GizmoIcons.IconType.PROGRADE), progradeColorValue); } } if (vertBar1Material != null) { float value = comp.ProcessVariable(vertBar1Variable).MassageToFloat(); if (float.IsNaN(value)) { value = 0.0f; } if (vertBar1UseLog10) { value = JUtil.PseudoLog10(value); } float vertBar1TexCoord = JUtil.DualLerp(vertBar1TextureLimit.x, vertBar1TextureLimit.y, vertBar1Limit.x, vertBar1Limit.y, value); vertBar1Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, vertBar1TexCoord + vertBar1TextureSize); GL.Vertex3(vertBar1Position.x, vertBar1Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar1TexCoord + vertBar1TextureSize); GL.Vertex3(vertBar1Position.x + vertBar1Position.z, vertBar1Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar1TexCoord - vertBar1TextureSize); GL.Vertex3(vertBar1Position.x + vertBar1Position.z, vertBar1Position.y + vertBar1Position.w, 0.0f); GL.TexCoord2(0.0f, vertBar1TexCoord - vertBar1TextureSize); GL.Vertex3(vertBar1Position.x, vertBar1Position.y + vertBar1Position.w, 0.0f); GL.End(); } if (vertBar2Material != null) { float value = comp.ProcessVariable(vertBar2Variable).MassageToFloat(); if (float.IsNaN(value)) { value = 0.0f; } if (vertBar2UseLog10) { value = JUtil.PseudoLog10(value); } float vertBar2TexCoord = JUtil.DualLerp(vertBar2TextureLimit.x, vertBar2TextureLimit.y, vertBar2Limit.x, vertBar2Limit.y, value); vertBar2Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, vertBar2TexCoord + vertBar2TextureSize); GL.Vertex3(vertBar2Position.x, vertBar2Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar2TexCoord + vertBar2TextureSize); GL.Vertex3(vertBar2Position.x + vertBar2Position.z, vertBar2Position.y, 0.0f); GL.TexCoord2(1.0f, vertBar2TexCoord - vertBar2TextureSize); GL.Vertex3(vertBar2Position.x + vertBar2Position.z, vertBar2Position.y + vertBar2Position.w, 0.0f); GL.TexCoord2(0.0f, vertBar2TexCoord - vertBar2TextureSize); GL.Vertex3(vertBar2Position.x, vertBar2Position.y + vertBar2Position.w, 0.0f); GL.End(); } if (overlayMaterial != null) { overlayMaterial.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0.0f, 0.0f, 0.0f); GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(screen.width, 0.0f, 0.0f); GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(screen.width, screen.height, 0.0f); GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0.0f, screen.height, 0.0f); GL.End(); } GL.PopMatrix(); return(true); }
public bool RenderPFD(RenderTexture screen, float aspect) { if (screen == null || !startupComplete || HighLogic.LoadedSceneIsEditor) { return(false); } // Analysis disable once CompareOfFloatsByEqualityOperator if (firstRenderComplete == false) { firstRenderComplete = true; ConfigureElements((float)screen.width, (float)screen.height); ballCamera.aspect = aspect; } GL.Clear(true, true, backgroundColorValue); ballCamera.targetTexture = screen; // Navball is rotated around the Y axis 180 degrees since the // original implementation had the camera positioned differently. // We still need MirrorX since KSP does something odd with the // gimbal navBall.transform.rotation = (rotateNavBall * MirrorX(stockNavBall.relativeGymbal)); RPMVesselComputer comp = RPMVesselComputer.Instance(vessel); if (heading != null) { heading.renderer.material.SetTextureOffset("_MainTex", new Vector2(JUtil.DualLerp(0f, 1f, 0f, 360f, comp.RotationVesselSurface.eulerAngles.y) - headingSpan / 2f, 0)); } Quaternion gymbal = stockNavBall.attitudeGymbal; if (FlightUIController.speedDisplayMode == FlightUIController.SpeedDisplayModes.Orbit) { Vector3 velocityVesselOrbitUnit = comp.Prograde; Vector3 radialPlus = comp.RadialOut; Vector3 normalPlus = comp.NormalPlus; MoveMarker(markerPrograde, velocityVesselOrbitUnit, gymbal); MoveMarker(markerRetrograde, -velocityVesselOrbitUnit, gymbal); MoveMarker(markerNormal, normalPlus, gymbal); MoveMarker(markerNormalMinus, -normalPlus, gymbal); MoveMarker(markerRadial, radialPlus, gymbal); MoveMarker(markerRadialMinus, -radialPlus, gymbal); JUtil.ShowHide(true, markerNormal, markerNormalMinus, markerRadial, markerRadialMinus); } else if (FlightUIController.speedDisplayMode == FlightUIController.SpeedDisplayModes.Surface) { Vector3 velocityVesselSurfaceUnit = vessel.srf_velocity.normalized; MoveMarker(markerPrograde, velocityVesselSurfaceUnit, gymbal); MoveMarker(markerRetrograde, -velocityVesselSurfaceUnit, gymbal); } else // FlightUIController.speedDisplayMode == FlightUIController.SpeedDisplayModes.Target { Vector3 targetDirection = FlightGlobals.ship_tgtVelocity.normalized; MoveMarker(markerPrograde, targetDirection, gymbal); MoveMarker(markerRetrograde, -targetDirection, gymbal); } if (vessel.patchedConicSolver != null && vessel.patchedConicSolver.maneuverNodes.Count > 0) { Vector3 burnVector = vessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(vessel.orbit).normalized; MoveMarker(markerManeuver, burnVector, gymbal); MoveMarker(markerManeuverMinus, -burnVector, gymbal); JUtil.ShowHide(true, markerManeuver, markerManeuverMinus); } if (FinePrint.WaypointManager.navIsActive() == true) { // MOARdV: Code for the waypoint marker based on https://github.com/Ninenium/NavHud/blob/master/Source/WaypointMarker.cs GameObject navWaypointIndicator = GameObject.Find("NavBall").transform.FindChild("vectorsPivot").FindChild("NavWaypoint").gameObject; Material material = navWaypointIndicator.renderer.sharedMaterial; markerNavWaypoint.renderer.material.mainTexture = material.mainTexture; markerNavWaypoint.renderer.material.mainTextureScale = Vector2.one; markerNavWaypoint.renderer.material.mainTextureOffset = Vector2.zero; if (string.IsNullOrEmpty(waypointColor)) { markerNavWaypoint.renderer.material.SetVector("_Color", material.GetVector("_Color")); } Vector3d waypointPosition = vessel.mainBody.GetWorldSurfacePosition(FinePrint.WaypointManager.navWaypoint.latitude, FinePrint.WaypointManager.navWaypoint.longitude, FinePrint.WaypointManager.navWaypoint.altitude); Vector3 waypointDirection = (waypointPosition - vessel.CoM).normalized; MoveMarker(markerNavWaypoint, waypointDirection, gymbal); JUtil.ShowHide(true, markerNavWaypoint); } ITargetable target = FlightGlobals.fetch.VesselTarget; if (target != null) { Vector3 targetSeparation = comp.TargetSeparation.normalized; MoveMarker(markerTarget, targetSeparation, gymbal); MoveMarker(markerTargetMinus, -targetSeparation, gymbal); var targetPort = target as ModuleDockingNode; if (targetPort != null) { // Thanks to Michael Enßlin Transform targetTransform = targetPort.transform; Transform selfTransform = vessel.ReferenceTransform; Vector3 targetOrientationVector = -targetTransform.up.normalized; Vector3 v1 = Vector3.Cross(selfTransform.up, targetTransform.forward); Vector3 v2 = Vector3.Cross(selfTransform.up, selfTransform.forward); float angle = Vector3.Angle(v1, v2); if (Vector3.Dot(selfTransform.up, Vector3.Cross(v1, v2)) < 0) { angle = -angle; } MoveMarker(markerDockingAlignment, targetOrientationVector, gymbal); markerDockingAlignment.transform.Rotate(Vector3.up, -angle); JUtil.ShowHide(true, markerDockingAlignment); } JUtil.ShowHide(true, markerTarget, markerTargetMinus); } JUtil.ShowHide(true, cameraBody, navBall, overlay, heading, markerPrograde, markerRetrograde); ballCamera.Render(); JUtil.ShowHide(false, cameraBody, navBall, overlay, heading, markerPrograde, markerRetrograde, markerManeuver, markerManeuverMinus, markerTarget, markerTargetMinus, markerNormal, markerNormalMinus, markerRadial, markerRadialMinus, markerDockingAlignment, markerNavWaypoint); return(true); }
public bool RenderHUD(RenderTexture screen, float cameraAspect) { if (screen == null || !startupComplete || HighLogic.LoadedSceneIsEditor) { return(false); } //屏幕不存在,启动不完全,在编辑器内三种条件下直接返回。 GL.Clear(true, true, backgroundColorValue); //擦除屏幕 Vector3 coM = vessel.findWorldCenterOfMass(); //质心位置 //这里的vessel变量是从InternalModule提取的。 Vector3 up = (coM - vessel.mainBody.position).normalized; //质心位置减去几何中心位置,求单位向量 Vector3 forward = vessel.GetTransform().up; //求从正在控制的驾驶舱测得的前向速度 Vector3 right = vessel.GetTransform().right; //求向右平移速度 Vector3 top = Vector3.Cross(right, forward); //求前两者的叉积,得到向上的方向 Vector3 north = Vector3.Exclude(up, (vessel.mainBody.position + (Vector3d)vessel.mainBody.transform.up * vessel.mainBody.Radius) - coM).normalized; Vector3d velocityVesselSurface = vessel.orbit.GetVel() - vessel.mainBody.getRFrmVel(coM); //轨道速度减去行星转速,得到地面速度 Vector3 velocityVesselSurfaceUnit = velocityVesselSurface.normalized; //速度的方向 float cosUp = Vector3.Dot(forward, up); //俯仰的余弦 float cosRoll = Vector3.Dot(top, up); //滚转的余弦 float sinRoll = Vector3.Dot(right, up); //滚转的正弦 var normalizedRoll = new Vector2(cosRoll, sinRoll); //滚转角速度的单位向量。 GL.PushMatrix(); //保存运行前的状态。第一次运行显然为空 foreach (InfoGauge gauge in gaugeList) //遍历信息条列表 { GL.LoadPixelMatrix(-0.5f * screen.width, 0.5f * screen.width, 0.5f * screen.height, -0.5f * screen.height); //载入屏幕矩阵,准备渲染 //原点在屏幕中心 GL.Viewport(new Rect(0, 0, screen.width, screen.height)); //载入视场 float value = comp.ProcessVariable(gauge.Variable).MassageToFloat(); //用来存读入的变量 if (float.IsNaN(value)) { value = 0.0f; } if (gauge.Material != null) //读到信息条用的贴图 { float midPointCoord; //贴图中点坐标。所有信息条统一用原本俯仰条的渲染方法。 Vector2 usedTextureSize = new Vector2(gauge.TextureLimit.y - gauge.TextureLimit.x, gauge.TextureLimit.w - gauge.TextureLimit.z); float textureOffset = usedTextureSize.x / gauge.Material.mainTexture.height; if (gauge.Use360Horizon)//超过上限之后翻转 { midPointCoord = JUtil.DualLerp(gauge.TextureLimit.z + 0.25f * usedTextureSize.y, gauge.TextureLimit.w - 0.25f * usedTextureSize.y, gauge.Limit.x, gauge.Limit.y, value); } else { midPointCoord = JUtil.DualLerp(gauge.TextureLimit.x, gauge.TextureLimit.y, gauge.Limit.x, gauge.Limit.y, value); } if (gauge.RotateWithVessel)//随载具滚转 { gauge.Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, midPointCoord + gauge.TextureSize); GL.Vertex3((cosRoll * gauge.Position.x + sinRoll * gauge.Position.y), (-sinRoll * gauge.Position.x + cosRoll * gauge.Position.y), 0.0f); GL.TexCoord2(1.0f, midPointCoord + gauge.TextureSize); GL.Vertex3((cosRoll * (gauge.Position.x + gauge.Position.z) + sinRoll * gauge.Position.y), (-sinRoll * (gauge.Position.x + gauge.Position.z) + cosRoll * gauge.Position.y), 0.0f); GL.TexCoord2(1.0f, midPointCoord - gauge.TextureSize); GL.Vertex3((cosRoll * (gauge.Position.x + gauge.Position.z) + sinRoll * (gauge.Position.y + gauge.Position.w)), (-sinRoll * (gauge.Position.x + gauge.Position.z) + cosRoll * (gauge.Position.y + gauge.Position.w)), 0.0f); GL.TexCoord2(0.0f, midPointCoord - gauge.TextureSize); GL.Vertex3((cosRoll * (gauge.Position.x) + sinRoll * (gauge.Position.y + gauge.Position.w)), (-sinRoll * (gauge.Position.x) + cosRoll * (gauge.Position.y + gauge.Position.w)), 0.0f); GL.End(); } else { gauge.Material.SetPass(0); GL.Begin(GL.QUADS); GL.TexCoord2(0.0f, midPointCoord + gauge.TextureSize); GL.Vertex3(gauge.Position.x, gauge.Position.y, 0.0f); GL.TexCoord2(1.0f, midPointCoord + gauge.TextureSize); GL.Vertex3(gauge.Position.x + gauge.Position.z, gauge.Position.y, 0.0f); GL.TexCoord2(1.0f, midPointCoord - gauge.TextureSize); GL.Vertex3(gauge.Position.x + gauge.Position.z, gauge.Position.y + gauge.Position.w, 0.0f); GL.TexCoord2(0.0f, midPointCoord - gauge.TextureSize); GL.Vertex3(gauge.Position.x, gauge.Position.y + gauge.Position.w, 0.0f); GL.End(); } } else { JUtil.LogErrorMessage(this, "Material is null"); } } GL.PopMatrix();//输出上述的矩阵 return(true); }
public void Update() { var scaleResults = new float[3]; for (int i = 0; i < 3; i++) { if (!scaleEnds[i].Get(out scaleResults[i])) { return; } } float scaledValue = Mathf.InverseLerp(scaleResults[0], scaleResults[1], scaleResults[2]); if (thresholdMode) { if (scaledValue >= threshold.x && scaledValue <= threshold.y) { if (flashingDelay > 0) { if (lastStateChange < Planetarium.GetUniversalTime() - flashingDelay) { if (currentState) { TurnOff(); } else { TurnOn(); } } } else { TurnOn(); } if (audioOutput != null && !alarmActive) { audioOutput.audio.Play(); alarmActive = true; } } else { TurnOff(); if (audioOutput != null) { audioOutput.audio.Stop(); alarmActive = false; } } } else { switch (mode) { case Mode.Rotation: Quaternion newRotation = longPath ? Quaternion.Euler(Vector3.Lerp(reverse ? vectorEnd : vectorStart, reverse ? vectorStart : vectorEnd, scaledValue)) : Quaternion.Slerp(reverse ? rotationEnd : rotationStart, reverse ? rotationStart : rotationEnd, scaledValue); controlledTransform.localRotation = initialRotation * newRotation; break; case Mode.Translation: controlledTransform.localPosition = initialPosition + Vector3.Lerp(reverse ? vectorEnd : vectorStart, reverse ? vectorStart : vectorEnd, scaledValue); break; case Mode.Scale: controlledTransform.localScale = initialScale + Vector3.Lerp(reverse ? vectorEnd : vectorStart, reverse ? vectorStart : vectorEnd, scaledValue); break; case Mode.Color: colorShiftRenderer.material.SetColor(colorName, Color.Lerp(reverse ? activeColor : passiveColor, reverse ? passiveColor : activeColor, scaledValue)); break; case Mode.TextureShift: foreach (string token in textureLayer.Split(',')) { affectedMaterial.SetTextureOffset(token.Trim(), Vector2.Lerp(reverse ? textureShiftEnd : textureShiftStart, reverse ? textureShiftStart : textureShiftEnd, scaledValue)); } break; case Mode.TextureScale: foreach (string token in textureLayer.Split(',')) { affectedMaterial.SetTextureScale(token.Trim(), Vector2.Lerp(reverse ? textureScaleEnd : textureScaleStart, reverse ? textureScaleStart : textureScaleEnd, scaledValue)); } break; case Mode.Animation: float lerp = JUtil.DualLerp(reverse ? 1f : 0f, reverse ? 0f : 1f, scaleResults[0], scaleResults[1], scaleResults[2]); if (float.IsNaN(lerp) || float.IsInfinity(lerp)) { lerp = reverse ? 1f : 0f; } anim[animationName].normalizedTime = lerp; break; } } }