void StepWand() { if (wandStream == null) { wandStream = Sound.CreateStream(5f); wandStreamInst = wandStream.Play(wandTipPrev); } if (wandModel == null) { wandModel = Model.FromFile("Wand.glb", Shader.UI); } if (wandFollow == null) { wandFollow = new LinePoint[10]; for (int i = 0; i < wandFollow.Length; i += 1) { wandFollow[i] = new LinePoint(Vec3.Zero, new Color(1, 1, 1, i / (float)wandFollow.Length), (i / (float)wandFollow.Length) * 0.01f + 0.001f); } } UI.HandleBegin("wand", ref wandPose, wandModel.Bounds); wandModel.Draw(Matrix.Identity); UI.HandleEnd(); Vec3 wandTip = wandPose.ToMatrix() * (wandModel.Bounds.center + wandModel.Bounds.dimensions.y * 0.5f * Vec3.Up); Vec3 wandVel = (wandTip - wandTipPrev) * Time.Elapsedf; float wandSpeed = wandVel.Magnitude * 100; int count = Math.Max(0, (int)(0.1f * 48000) - (wandStream.TotalSamples - wandStream.CursorSamples)); if (wandSamples.Length < count) { wandSamples = new float[count]; } for (int i = 0; i < count; i++) { wandIntensity = Math.Min(1, SKMath.Lerp(wandIntensity, wandSpeed, 0.001f)); wandTime += (1 / 48000.0) * (30000 * wandIntensity + 2000); wandSamples[i] = (float)Math.Sin(wandTime) * wandIntensity; } wandStreamInst.Position = wandTip; wandStream.WriteSamples(wandSamples, count); for (int i = 0; i < wandFollow.Length - 1; i++) { wandFollow[i].pt = wandFollow[i + 1].pt; } wandFollow[wandFollow.Length - 1].pt = wandTip; Lines.Add(wandFollow); wandTipPrev = wandTip; }
void StepMenu(Hand hand) { // Animate the menu a bit float time = (Time.Elapsedf * 24); menuPose.position = Vec3.Lerp(menuPose.position, destPose.position, time); menuPose.orientation = Quat.Slerp(menuPose.orientation, destPose.orientation, time); activation = SKMath.Lerp(activation, 1, time); // Pre-calculate some circle traversal values HandRadialLayer layer = layers[activeLayer]; int count = layer.items.Length; float step = 360 / count; float halfStep = step / 2; // Push the Menu's pose onto the stack, so we can draw, and work // in local space. Hierarchy.Push(menuPose.ToMatrix(activation)); // Calculate the status of the menu! Vec3 tipWorld = hand[FingerId.Index, JointId.Tip].position; Vec3 tipLocal = Hierarchy.ToLocal(tipWorld); float magSq = tipLocal.MagnitudeSq; bool onMenu = tipLocal.z > -0.02f && tipLocal.z < 0.02f; bool focused = onMenu && magSq > minDist * minDist; bool selected = onMenu && magSq > midDist * midDist; bool cancel = magSq > maxDist * maxDist; // Find where our finger is pointing to, and draw that float fingerAngle = (float)Math.Atan2(tipLocal.y, tipLocal.x) * Units.rad2deg - (layer.startAngle + angleOffset); while (fingerAngle < 0) { fingerAngle += 360; } int angleId = (int)(fingerAngle / step); Lines.Add(Vec3.Zero, new Vec3(tipLocal.x, tipLocal.y, 0), Color.White * 0.5f, 0.001f); // Draw the menu inner and outer circles Lines.Add(circle); Lines.Add(innerCircle); // Now draw each of the menu items! for (int i = 0; i < count; i++) { float currAngle = i * step + layer.startAngle + angleOffset; bool highlightText = focused && angleId == i; bool highlightLine = highlightText || (focused && (angleId + 1) % count == i); Vec3 dir = Vec3.AngleXY(currAngle); Lines.Add(dir * minDist, dir * maxDist, highlightLine ? Color.White : Color.White * 0.5f, highlightLine?0.002f:0.001f); Text.Add(layer.items[i].name, Matrix.TRS(Vec3.AngleXY(currAngle + halfStep) * midDist, Quat.FromAngles(0, 0, currAngle + halfStep - 90), highlightText?1.2f:1), TextAlign.XCenter | TextAlign.YBottom); } // Done with local work Hierarchy.Pop(); // Execute any actions that were discovered // But not if we're still in the process of animating, interaction values // could be pretty incorrect when we're still lerping around. if (activation < 0.95f) { return; } if (selected) { SelectItem(layer.items[angleId], tipWorld, (angleId + 0.5f) * step); } if (cancel) { Close(); } }