/** * HUD whose sole purpose is to preview the output of some of the math functions on a graph. * To preview a function, simply enter its name in the Command property of the Open HUD node. * * Supported functions: * - InterpolationOvershoot * - InterpolationSpring * - InterpolationBounce * - BounceAnimation * - InterpolationAnticipate * - InterpolationAnticipateSub * - InterpolationDecelerate * - InterpolationEaseInEaseOut * * NOTE: This can be extended to support more functions, if needed. * * Controls: * - Parameter 1 - W/S * - Parameter 2 - A/D * - Parameter 3 - 1/4/scroll (if not used, these also control Parameter 1) * - Parameter 4 - 2/3 (if not used, these also control Parameter 2) * * NOTE: As of right now, none of the functions use more than 2 parameters. */ class Drew_HUDElement_HatMathGraphPreviewer extends Hat_HUDElement; const GRAPH_SAMPLE_COUNT = 200; const GRAPH_PADDING = 0.15f; var string FunctionNameDisplay; var string ParameterDisplay; var Vector2D GraphRangeStart, GraphRangeEnd; var int VerticalLineAmount, HorizontalLineAmount; struct DebugGraphParameter { var string Name; var float StepValue; var int StepCount; var bool IsBool; var transient float CurrentValue; }; var DebugGraphParameter P1, P2, P3, P4; delegate float MathFunctionOutput(float X) { return 0.5f; } function OnOpenHUD(HUD H, optional string command) { Super.OnOpenHUD(H, command); switch (Locs(command)) { case "interpolationovershoot": FunctionNameDisplay = "InterpolationOvershoot(0, 1, X, Tension)"; MathFunctionOutput = InterpolationOvershoot; GraphRangeStart.Y = 3.f; HorizontalLineAmount = 7; P1.Name = "Tension"; P1.StepValue = 0.5f; P1.StepCount = 4; RefreshParameter(P1); break; case "interpolationspring": FunctionNameDisplay = "InterpolationSpring(0, 1, X, Factor, Bounce Rate)"; MathFunctionOutput = InterpolationSpring; GraphRangeStart.Y = 2.f; HorizontalLineAmount = 5; P1.Name = "Factor"; P1.StepValue = 0.05f; P1.StepCount = 8; RefreshParameter(P1); P2.Name = "Bounce Rate"; P2.StepValue = 0.5f; P2.StepCount = 20; RefreshParameter(P2); break; case "interpolationbounce": FunctionNameDisplay = "InterpolationBounce(1, 0, X, Strength)"; MathFunctionOutput = InterpolationBounce; GraphRangeEnd.X = 1.5f; VerticalLineAmount = 7; P1.Name = "Strength"; P1.StepValue = 0.1f; P1.StepCount = 10; RefreshParameter(P1); break; case "bounceanimation": FunctionNameDisplay = "BounceAnimation(X, Scale, BounceCount)"; MathFunctionOutput = BounceAnimation; GraphRangeStart.Y = 2.f; GraphRangeEnd.Y = 1.f; HorizontalLineAmount = 5; P1.Name = "Scale"; P1.StepValue = 0.1f; P1.StepCount = 5; RefreshParameter(P1); P2.Name = "Bounce Count"; P2.StepValue = 1.f; P2.StepCount = 4; RefreshParameter(P2); break; case "interpolationanticipate": FunctionNameDisplay = "InterpolationAnticipate(0, 1, X, Tension, Overshoot)"; MathFunctionOutput = InterpolationAnticipate; GraphRangeStart.Y = 2.f; GraphRangeEnd.Y = -1.f; HorizontalLineAmount = 7; P1.Name = "Tension"; P1.StepValue = 0.5f; P1.StepCount = 6; RefreshParameter(P1); P2.Name = "Overshoot"; P2.StepValue = 1.f; P2.StepCount = 1; P2.IsBool = True; RefreshParameter(P2); break; case "interpolationanticipatesub": FunctionNameDisplay = "InterpolationAnticipateSub(X, S, Subtract)"; MathFunctionOutput = InterpolationAnticipateSub; P1.Name = "S"; P1.StepValue = 0.1f; P1.StepCount = 0; RefreshParameter(P1); P2.Name = "Subtract"; P2.StepValue = 1.f; P2.StepCount = 1; P2.IsBool = True; RefreshParameter(P2); break; case "interpolationdecelerate": FunctionNameDisplay = "InterpolationDecelerate(0, 1, X, Factor)"; MathFunctionOutput = InterpolationDecelerate; P1.Name = "Factor"; P1.StepValue = 0.1f; P1.StepCount = 10; RefreshParameter(P1); break; case "interpolationeaseineaseout": FunctionNameDisplay = "InterpolationEaseInEaseOut(0, 1, X)"; MathFunctionOutput = InterpolationEaseInEaseOut; break; } RefreshParameterDisplay(); } function RefreshParameter(out DebugGraphParameter P) { if (P.IsBool) P.StepCount = Clamp(P.StepCount, 0, 1); P.CurrentValue = P.StepValue * P.StepCount; } function RefreshParameterDisplay() { ParameterDisplay = ""; AppendParameterDisplayForParameter(P1); AppendParameterDisplayForParameter(P2); AppendParameterDisplayForParameter(P3); AppendParameterDisplayForParameter(P4); } function AppendParameterDisplayForParameter(out DebugGraphParameter P) { if (P.StepValue == 0.f) return; if (ParameterDisplay != "") ParameterDisplay $= " , "; if (P.IsBool) ParameterDisplay $= (P.Name $ " = " $ Bool(P.CurrentValue)); else ParameterDisplay $= (P.Name $ " = " $ PrettyNumberRounding(P.CurrentValue)); } function bool OnPressUp(HUD H, bool menu, bool release) { if (release) return false; if (menu && P3.StepValue != 0.f) { P3.StepCount++; RefreshParameter(P3); } else { P1.StepCount++; RefreshParameter(P1); } RefreshParameterDisplay(); return true; } function bool OnPressDown(HUD H, bool menu, bool release) { if (release) return false; if (menu && P3.StepValue != 0.f) { P3.StepCount--; RefreshParameter(P3); } else { P1.StepCount--; RefreshParameter(P1); } RefreshParameterDisplay(); return true; } function bool OnPressLeft(HUD H, bool menu, bool release) { if (release) return false; if (menu && P4.StepValue != 0.f) { P4.StepCount--; RefreshParameter(P4); } else { P2.StepCount--; RefreshParameter(P2); } RefreshParameterDisplay(); return true; } function bool OnPressRight(HUD H, bool menu, bool release) { if (release) return false; if (menu && P4.StepValue != 0.f) { P4.StepCount++; RefreshParameter(P4); } else { P2.StepCount++; RefreshParameter(P2); } RefreshParameterDisplay(); return true; } function bool Render(HUD H) { local Vector2D GraphStart, GraphEnd; local float MinClip, Length, Ratio, PosX, PosY, NextPosX, ValueX, TextSize; local int i; local TextAlign TA; local bool InBatched; if (!Super.Render(H)) return false; H.Canvas.SetDrawColor(0, 0, 0, 255); H.Canvas.SetPos(0.f, 0.f); H.Canvas.DrawRect(H.Canvas.ClipX, H.Canvas.ClipY); MinClip = FMin(H.Canvas.ClipX, H.Canvas.ClipY); TextSize = MinClip * 0.0007f; GraphStart.X = MinClip * GRAPH_PADDING; GraphStart.Y = GraphStart.X; GraphEnd.X = H.Canvas.ClipX - GraphStart.X; GraphEnd.Y = H.Canvas.ClipY - GraphStart.Y; H.Canvas.SetDrawColor(100, 100, 100, 255); H.Canvas.Font = class'Hat_FontInfo'.static.GetDefaultFont("0123456789."); // Vertical lines if (VerticalLineAmount >= 2) { PosY = (GraphStart.Y + GraphEnd.Y) * 0.5f; Length = GraphEnd.Y - GraphStart.Y; for (i = 0; i < VerticalLineAmount; i++) { Ratio = Float(i) / (VerticalLineAmount - 1.f); PosX = Lerp(GraphStart.X, GraphEnd.X, Ratio); DrawCenter(H, PosX, PosY, 2.f, Length, H.Canvas.DefaultTexture); if (i == 0) TA = TextAlign_Left; else TA = TextAlign_Center; DrawText(H.Canvas, PrettyNumberRounding(Lerp(GraphRangeStart.X, GraphRangeEnd.X, Ratio)), PosX, GraphEnd.Y + TextSize * 30.f, TextSize, TextSize, TA); } } // Horizontal lines if (HorizontalLineAmount >= 2) { PosX = (GraphStart.X + GraphEnd.X) * 0.5f; Length = GraphEnd.X - GraphStart.X; for (i = 0; i < HorizontalLineAmount; i++) { Ratio = Float(i) / (HorizontalLineAmount - 1.f); PosY = Lerp(GraphStart.Y, GraphEnd.Y, Ratio); DrawCenter(H, PosX, PosY, Length, 2.f, H.Canvas.DefaultTexture); if (i == HorizontalLineAmount - 1) TA = TextAlign_BottomRight; else TA = TextAlign_Right; DrawText(H.Canvas, PrettyNumberRounding(Lerp(GraphRangeStart.Y, GraphRangeEnd.Y, Ratio)), GraphStart.X - TextSize * 10.f, PosY, TextSize, TextSize, TA); } } H.Canvas.SetDrawColor(255, 255, 255, 255); NextPosX = GraphStart.X; InBatched = H.Canvas.StartBatchedRendering(); for (i = 0; i < GRAPH_SAMPLE_COUNT; i++) { PosX = NextPosX; NextPosX = Lerp(GraphStart.X, GraphEnd.X, Float(i + 1) / GRAPH_SAMPLE_COUNT); ValueX = Lerp(GraphRangeStart.X, GraphRangeEnd.X, Float(i) / (GRAPH_SAMPLE_COUNT - 1.f)); PosY = Lerp(GraphStart.Y, GraphEnd.Y, (MathFunctionOutput(ValueX) - GraphRangeStart.Y) / (GraphRangeEnd.Y - GraphRangeStart.Y)); DrawCenterLeft(H, PosX, PosY, NextPosX - PosX, 2.f, H.Canvas.DefaultTexture); } if (InBatched) H.Canvas.EndBatchedRendering(); if (FunctionNameDisplay != "") { H.Canvas.SetDrawColor(255, 255, 200, 255); H.Canvas.Font = class'Hat_FontInfo'.static.GetDefaultFont(FunctionNameDisplay); DrawText(H.Canvas, FunctionNameDisplay, H.Canvas.ClipX * 0.5f, TextSize * 1.5f * 55.f, TextSize * 1.5f, TextSize * 1.5f, TextAlign_Center); } if (ParameterDisplay != "") { H.Canvas.SetDrawColor(255, 255, 255, 255); H.Canvas.Font = class'Hat_FontInfo'.static.GetDefaultFont(ParameterDisplay); DrawText(H.Canvas, ParameterDisplay, H.Canvas.ClipX * 0.5f, H.Canvas.ClipY - TextSize * 55.f, TextSize, TextSize, TextAlign_Center); } return true; } function string PrettyNumberRounding(float InFloat) { local int Number, Decimal; Number = Round(InFloat * 1000.f); Decimal = Number % 1000; Number /= 1000; while (Decimal != 0 && Decimal % 10 == 0) Decimal /= 10; if (Decimal == 0) return String(Number); else return (Decimal < 0 ? "-" : "") $ Int(Abs(Number)) $ "." $ Int(Abs(Decimal)); } // Math functions. function float InterpolationOvershoot(float X) { return class'Hat_Math'.static.InterpolationOvershoot(0.f, 1.f, X, P1.CurrentValue); } function float InterpolationSpring(float X) { return class'Hat_Math'.static.InterpolationSpring(0.f, 1.f, X, P1.CurrentValue, P2.CurrentValue); } function float InterpolationBounce(float X) { return class'Hat_Math'.static.InterpolationBounce(1.f, 0.f, X, P1.CurrentValue); } function float BounceAnimation(float X) { return class'Hat_Math'.static.BounceAnimation(X, P1.CurrentValue, Round(P2.CurrentValue)); } function float InterpolationAnticipate(float X) { return class'Hat_Math'.static.InterpolationAnticipate(0.f, 1.f, X, P1.CurrentValue, Bool(P2.CurrentValue)); } function float InterpolationAnticipateSub(float X) { return class'Hat_Math'.static.InterpolationAnticipateSub(X, P1.CurrentValue, Bool(P2.CurrentValue)); } function float InterpolationDecelerate(float X) { return class'Hat_Math'.static.InterpolationDecelerate(0.f, 1.f, X, P1.CurrentValue); } function float InterpolationEaseInEaseOut(float X) { return class'Hat_Math'.static.InterpolationEaseInEaseOut(0.f, 1.f, X); } defaultproperties { FunctionNameDisplay = "Missing command! (read script header)" GraphRangeStart = (X = 0.f, Y = 1.f) GraphRangeEnd = (X = 1.f, Y = 0.f) VerticalLineAmount = 5 HorizontalLineAmount = 5 }