public SliderNode( AParentSceneNode parent, Transform localTransform, // what parameter does this slider drag? Parameter parameter, // at what angle is the slider oriented? float rotation, // how long is the slider in screen space? int screenLength, // how far is the slider's origin from the transform's translation, in screen space? int originScreenOffset, // what is the slider's label? string label) : base(parent, localTransform, label) { m_parameter = parameter; m_rotation = rotation; m_screenLength = screenLength; m_originScreenOffset = originScreenOffset; // calculate the endpoints m_zeroEnd = ValueToLocal(0); m_oneEnd = ValueToLocal(1); double absRotation = Math.IEEERemainder(rotation, Math.PI * 2); if (absRotation < 0) { absRotation += Math.PI * 2; } m_label = new TextNode(this, label + "_text"); bool overPi = absRotation > Math.PI; m_label.Alignment = overPi ? Alignment.TopLeft : Alignment.TopRight; m_label.Text.Append(label); m_label.LocalTransform = new Transform(m_oneEnd, new Vector2(0.7f)); // seems the line rotation and label rotation go in opposite directions, feh! m_label.Rotation = -rotation + (float)(Math.PI / 2) + (overPi ? (float)Math.PI : 0); m_fullLine = new LineNode(this, "fullLine"); m_fullLine.SetEndpoints(m_zeroEnd, m_oneEnd); m_sliderLine = new LineNode(this, "sliderLine"); m_sliderLine.LocalTransform = new Transform(Vector2.Zero, new Vector2(3f)); // 3-pixel wide line Value = m_parameter[0]; }
public BeatNode( AParentSceneNode parent, Transform localTransform, string label, // are we filling in every beat, or just the current beat? bool fillInEveryBeat, // by how much do we scale down our texture when rendering a quarter note? float textureScale, Func<Duration<Sample>> trackLengthFunc, Func<int> initialBeatFunc, Func<Color> colorFunc) : base(parent, localTransform, label) { m_fillInEveryBeat = fillInEveryBeat; m_textureScale = textureScale; m_trackLengthFunc = trackLengthFunc; m_initialBeatFunc = initialBeatFunc; m_colorFunc = colorFunc; }
public TextSpriteNode( AParentSceneNode parent, Transform localTransform, string label, Texture2D background, Texture2D highlight) : base(parent, localTransform, label) { m_spriteNode = new SpriteNode(this, label + "_sprite", background); m_spriteNode.Origin = new Vector2(0.5f); m_textNode = new TextNode(this, label + "_text"); m_textNode.Alignment = Alignment.Centered; m_textNode.Text.Append(label); m_textNode.LocalTransform = new Transform(Vector2.Zero, new Vector2(0.6f)); m_highlightSpriteNode = new SpriteNode(this, label + "_highlight", highlight); m_highlightSpriteNode.Origin = new Vector2(0.5f); }
protected override void DoRender( Moment now, GraphicsDevice graphicsDevice, ISpriteBatch spriteBatch, TextureContent content, HolofunkView view, Transform parentTransform, int depth) { bool positionMirrored = SecondaryViewOption == SecondaryViewOption.PositionMirrored && view == HolofunkView.Secondary; Vector2 p0 = m_p0 + parentTransform.Translation; Vector2 p1 = m_p1 + parentTransform.Translation; if (positionMirrored) { p0 = new Vector2(spriteBatch.Viewport.X - p0.X, p0.Y); p1 = new Vector2(spriteBatch.Viewport.X - p1.X, p1.Y); } Vector2 diff = Vector2.Subtract(p1, p0); float angleRadians = (float)Math.Atan2(diff.Y, diff.X); float length = (float)Math.Sqrt(diff.X * diff.X + diff.Y * diff.Y) / 2; // Use NonPremultiplied, as our sprite textures are not premultiplied spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); spriteBatch.Draw( content.TinyDot, p0, null, Color, angleRadians, new Vector2(0f, 1f), // we pivot around the center of the left edge of the 2x2 square new Vector2(length, LocalTransform.Scale.Y), SpriteEffects.None, 0); spriteBatch.End(); }
internal TrackNode( AParentSceneNode parent, Transform transform, string label, TextureContent content, int id, SparseSampleByteStream videoStream, bool fillInEveryBeat, Func<float> levelRatioFunc, Func<Color> circleColorFunc, Func<Color> videoColorFunc, Func<Duration<Sample>> trackDurationFunc, Func<int> initialBeatFunc, Func<Color> beatColorFunc, Func<float> videoRateFunc) : base(parent, transform, label) { m_id = id; m_levelRatioFunc = levelRatioFunc; m_circleColorFunc = circleColorFunc; m_videoColorFunc = videoColorFunc; m_beatColorFunc = beatColorFunc; m_videoRateFunc = videoRateFunc; // create this first so it is Z-ordered behind m_soundNode m_selectNode = new SpriteNode(this, "TrackHighlight", content.FilledCircle); m_selectNode.Color = new Color((byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80); m_selectNode.Origin = new Vector2(0.5f); m_soundNode = new SpriteNode(this, "TrackSound", content.FilledCircle); m_soundNode.Color = Color.Blue; m_soundNode.Origin = new Vector2(0.5f); m_videoNode = new SpriteNode(this, "Headshot", content.NewDynamicTexture(MagicNumbers.HeadCaptureSize, MagicNumbers.HeadCaptureSize)); m_videoNode.Origin = new Vector2(0.5f); m_videoNode.LocalTransform = new Transform(new Vector2(0), new Vector2(MagicNumbers.HeadRatio)); m_videoNode.SetSecondaryViewOption(SecondaryViewOption.TextureMirrored); m_videoStream = videoStream; m_beatNode = new BeatNode( this, // move it down a bit from the sprite node new Transform(new Vector2(0, 75)), "TrackBeats", fillInEveryBeat, MagicNumbers.MeasureCircleScale, trackDurationFunc, initialBeatFunc, beatColorFunc); m_beatNode.SetSecondaryViewOption(SecondaryViewOption.PositionMirrored); // we always mirror track node position SetSecondaryViewOption(SecondaryViewOption.PositionMirrored); m_lastVideoFrame = default(Slice<Frame, byte>); }
protected override void DoRender(Moment now, GraphicsDevice graphicsDevice, ISpriteBatch spriteBatch, TextureContent content, HolofunkView view, Transform parentTransform, int depth) { m_videoRateCounter += m_videoRateFunc(); if (m_videoRateCounter >= 1f) { m_videoRateCounter -= 1f; lock (this) { if (VideoStream != null) { s_totalRenders++; Slice<Frame, byte> videoImage = VideoStream.GetClosestSliver(now.Time + MagicNumbers.LatencyCompensationDuration); if (!videoImage.IsEmpty()) { if (videoImage.Equals(m_lastVideoFrame)) { // skip the setData s_redundantSetDatas++; } else { // blast the data in there with a single pointer-based memory copy videoImage.RawAccess((array, offset, count) => m_videoNode.Texture.SetData(array, (int)offset, (int)count)); m_lastVideoFrame = videoImage; } } } else { // ain't nothing to show m_videoNode.Texture.SetData(BlankTextureData); } } } base.DoRender(now, graphicsDevice, spriteBatch, content, view, parentTransform, depth); }
/// <summary>Combine the two transforms by adding their translations and multiplying their scales, /// WITHOUT scaling their translations in any way.</summary> public Transform CombineWith(Transform other) { return new Transform(Translation + other.Translation, Scale * other.Scale); }
/// <summary>Render this AParentSceneNode by rendering all its children.</summary> protected override void DoRender( Moment now, GraphicsDevice graphicsDevice, ISpriteBatch spriteBatch, TextureContent content, HolofunkView view, Transform parentTransform, int depth) { Transform combinedTransform = parentTransform.CombineWith(LocalTransform); if (view == HolofunkView.Secondary && SecondaryViewOption == SecondaryViewOption.PositionMirrored) { combinedTransform = new Transform( new Vector2( spriteBatch.Viewport.X - combinedTransform.Translation.X, combinedTransform.Translation.Y), combinedTransform.Scale); } Spam.Graphics.WriteLine(new string(' ', depth * 4) + Label + ": parentTransform " + parentTransform + ", localTransform " + LocalTransform + ", combinedTransform " + combinedTransform); // m_children must only be enumerated / mutated under lock (this) lock (this) { m_childSnapshot.AddRange(m_children); } for (int i = 0; i < m_childSnapshot.Count; i++) { m_childSnapshot[i].Render(now, graphicsDevice, spriteBatch, content, view, combinedTransform, depth + 1); } // note that clearing preserves the capacity in the list, so no reallocation on next render m_childSnapshot.Clear(); }
protected AParentSceneNode(AParentSceneNode parent, Transform localTransform, string label) : base(parent, localTransform, label) { }
protected override void DoRender( Moment now, GraphicsDevice graphicsDevice, ISpriteBatch spriteBatch, TextureContent content, HolofunkView view, Transform parentTransform, int depth) { Transform combinedTransform = parentTransform.CombineWith(LocalTransform); spriteBatch.Begin(); Vector2 textSize = content.SpriteFont.MeasureString(m_text); Vector2 origin = Vector2.Zero; if (Alignment == Alignment.Centered) { origin = textSize / 2; } else if (Alignment == Alignment.TopRight) { origin = new Vector2(textSize.X, 0); } spriteBatch.DrawString( content.SpriteFont, m_text, combinedTransform.Translation, Color, Rotation, origin, combinedTransform.Scale.X, SpriteEffects.None, 0); spriteBatch.End(); }
/// <summary> /// Start recording a new loopie; return null if we have no free streams. /// </summary> internal Loopie StartRecording(Moment now, Transform handPosition, bool isRight) { Loopie ret = m_parent.StartRecordingNewLoopie(now, m_playerIndex, isRight, AsioChannel, handPosition); return ret; }
protected override void DoRender( Moment now, GraphicsDevice graphicsDevice, ISpriteBatch spriteBatch, TextureContent content, HolofunkView view, Transform parentTransform, int depth) { if (m_totalBeats == 0) { // there is no actual track here; we do not render return; } Transform combinedTransform = parentTransform.CombineWith(LocalTransform); // How many measures? long measureCount = (m_totalBeats + 3) / 4; // note that the quarter-circle only takes up one quarter of quarterCircleRect; this is deliberate Rectangle quarterCircleRect = TextureRect(content.QuarterHollowCircle, combinedTransform.Scale * m_textureScale); Vector2 measuresOrigin = combinedTransform.Translation; measuresOrigin.X -= ((Math.Min(4, measureCount) * quarterCircleRect.Width) / 2); Color color = m_colorFunc(); Spam.Graphics.WriteLine(new string(' ', depth * 4) + Label + ": parentTransform " + parentTransform + ", localTransform " + LocalTransform + ", combinedTransform " + combinedTransform + ", color " + color.ToString()); for (int b = 0; b < m_totalBeats; b++) { float filledness; if (m_fillInEveryBeat) { if (b < m_currentBeat) { filledness = 1; } else if (b == m_currentBeat) { filledness = (float)m_fractionalBeat; } else { filledness = 0; } } else { if (b == m_currentBeat) { filledness = (float)(1 - m_fractionalBeat); } else { filledness = 0; } } DrawQuarterCircle(spriteBatch, content, quarterCircleRect, measuresOrigin, b, color, filledness, depth); } }
public GroupNode(AParentSceneNode parent, Transform localTransform, string label) : base(parent, localTransform, label) { }
public SpriteBatchWrapper(SpriteBatch spriteBatch, Vector2 viewport, Transform transform) { m_spriteBatch = spriteBatch; m_viewport = viewport; m_transform = transform; }
protected override void LoadContent() { base.LoadContent(); float scale = GraphicsDevice.PresentationParameters.BackBufferHeight / m_viewportSize.Y; float scaledViewportWidth = m_viewportSize.X * scale; float scaledViewportOffset = (GraphicsDevice.PresentationParameters.BackBufferWidth - scaledViewportWidth) / 2; Transform transform = new Transform(new Vector2(scaledViewportOffset, 0), new Vector2(scale)); m_spriteBatch = new SpriteBatchWrapper(new SpriteBatch(GraphicsDevice), ViewportSize, transform); var holofunkContent = new HolofunkTextureContent(Content, GraphicsDevice); m_model = new HolofunkModel( GraphicsDevice, m_clock, m_holofunkBass, m_kinect, holofunkContent, m_viewportSize, m_clock.BPM, m_audioAllocator, m_videoAllocator); }
protected override void DoRender( Moment now, GraphicsDevice graphicsDevice, ISpriteBatch spriteBatch, TextureContent content, HolofunkView view, Transform parentTransform, int depth) { // no texture = no-op if (m_texture == null) { return; } int left = -(int)((float)m_texture.Width * m_origin.X); int top = -(int)((float)m_texture.Height * m_origin.Y); Rectangle rect = new Rectangle(left, top, m_texture.Width, m_texture.Height); Transform combinedTransform = parentTransform.CombineWith(LocalTransform); Rectangle transformedRect = rect * combinedTransform; Spam.Graphics.WriteLine(new string(' ', depth * 4) + Label + ": parentTransform " + parentTransform + ", localTransform " + LocalTransform + ", combinedTransform " + combinedTransform + "; start rect " + rect.FormatToString() + "; transformedRect " + transformedRect.FormatToString()); Texture2D texture = m_texture; SpriteEffects effects = SpriteEffects.None; if (view == HolofunkView.Secondary) { if ((SecondaryViewOption & SecondaryViewOption.TextureMirrored) != 0) { effects = SpriteEffects.FlipHorizontally; } if ((SecondaryViewOption & SecondaryViewOption.PositionMirrored) != 0) { // need to flip transformedRect around center of viewport int newLeft = (int)spriteBatch.Viewport.X - transformedRect.Right; transformedRect = new Rectangle(newLeft, transformedRect.Y, transformedRect.Width, transformedRect.Height); } if ((SecondaryViewOption & SecondaryViewOption.SecondTexture) != 0) { HoloDebug.Assert(m_secondaryTexture != null); texture = m_secondaryTexture; } } Color color = m_color; if (view == HolofunkView.Secondary && m_secondaryColor.HasValue) { color = m_secondaryColor.Value; } // Use NonPremultiplied, as our sprite textures are not premultiplied spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); spriteBatch.Draw( texture, transformedRect, null, color, 0, m_origin, effects, 0); spriteBatch.End(); }