Example #1
0
        /// <summary>
        /// Draw a single RoundLine.  Usually you want to draw a list of RoundLines
        /// at a time instead for better performance.
        /// </summary>
        public void Draw(RoundLine roundLine, float lineRadius, Color lineColor,
                         float time, string techniqueName)
        {
            if (_device == null)
            {
                throw new Exception("RoundlineManager Draw was called before initializing.");
            }

            SetParams(lineRadius, lineColor, time, techniqueName);

            int iData = 0;

            _translationData[iData++] = roundLine.P0.X;
            _translationData[iData++] = roundLine.P0.Y;
            _translationData[iData++] = roundLine.Rho;
            _translationData[iData]   = roundLine.Theta;
            _instanceDataParameter.SetValue(_translationData);

            _effect.Begin();
            var pass = _effect.CurrentTechnique.Passes[0];

            pass.Begin();

            _device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _numVertices, 0, _numPrimitivesPerInstance * 1);
            NumLinesDrawn += 1;

            pass.End();

            _effect.End();
        }
        /// <summary>
        /// Draw a single RoundLine.  Usually you want to draw a list of RoundLines
        /// at a time instead for better performance.
        /// </summary>
        public void Draw(RoundLine roundLine, float lineRadius, Color lineColor, Matrix viewProjMatrix,
            float time, string techniqueName)
        {
            device.SetVertexBuffer(vb);
            device.Indices = ib;

            viewProjMatrixParameter.SetValue(viewProjMatrix);
            timeParameter.SetValue(time);
            lineColorParameter.SetValue(lineColor.ToVector4());
            lineRadiusParameter.SetValue(lineRadius);
            blurThresholdParameter.SetValue(BlurThreshold);

            int iData = 0;
            translationData[iData++] = roundLine.P0.X;
            translationData[iData++] = roundLine.P0.Y;
            translationData[iData++] = roundLine.Rho;
            translationData[iData++] = roundLine.Theta;
            instanceDataParameter.SetValue(translationData);

            if (techniqueName == null)
                effect.CurrentTechnique = effect.Techniques[0];
            else
                effect.CurrentTechnique = effect.Techniques[techniqueName];
            EffectPass pass = effect.CurrentTechnique.Passes[0];
            pass.Apply();

            int numInstancesThisDraw = 1;
            device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, numVertices, 0, numPrimitivesPerInstance * numInstancesThisDraw);
            NumLinesDrawn += numInstancesThisDraw;
        }
        public override void OnDraw(GraphicsDevice graphicsDevice, VikingXNA.Scene scene, BasicEffect basicEffect)
        {
            if (this.oldMouse == null)
                return;

            GlobalPrimitives.DrawCircle(graphicsDevice, basicEffect, transformedPos, putativeLoc.Radius, linecolor);

            Vector3 target;
            if (nearestParent != null)
            {
                SectionLocationsViewModel sectionAnnotations = AnnotationOverlay.GetAnnotationsForSection(Parent.Section.Number);
                if (sectionAnnotations == null)
                    return;

                //Snap the line to a nearby target if it exists
                GridVector2 targetPos = nearestParent.VolumePosition;

                /*
                bool success = sectionAnnotations.TryGetPositionForLocation(nearestParent, out targetPos);
                if (!success)
                    return;
                */

                target = new Vector3((float)targetPos.X, (float)targetPos.Y, 0f);
            }
            else
            {
                //Otherwise use the old mouse position
                target = new Vector3((float)this.oldWorldPosition.X, (float)oldWorldPosition.Y, 0f);
            }

            RoundLine lineToParent = new RoundLine((float)transformedPos.X, (float)transformedPos.Y, (float)target.X, (float)target.Y);

            Parent.LineManager.Draw(lineToParent, (float)(putativeLoc.Radius / 6.0), linecolor, basicEffect.View * basicEffect.Projection, 1, null);

            base.OnDraw(graphicsDevice, scene, basicEffect);
        }
Example #4
0
        /// <summary>
        /// Draw a single RoundLine.  Usually you want to draw a list of RoundLines
        /// at a time instead for better performance.
        /// </summary>
        public void Draw(RoundLine roundLine, float lineRadius, Color lineColor, Matrix viewProjMatrix,
            float time, string techniqueName)
        {
            VertexDeclaration oldVertexDeclaration = device.VertexDeclaration;
            device.VertexDeclaration = vdecl;
            device.Vertices[0].SetSource(vb, 0, bytesPerVertex);
            device.Indices = ib;

            viewProjMatrixParameter.SetValue(viewProjMatrix);
            timeParameter.SetValue(time);
            lineColorParameter.SetValue(lineColor.ToVector4());
            lineRadiusParameter.SetValue(lineRadius);
            blurThresholdParameter.SetValue(BlurThreshold);

            int iData = 0;
            translationData[iData++] = roundLine.P0.X;
            translationData[iData++] = roundLine.P0.Y;
            translationData[iData++] = roundLine.Rho;
            translationData[iData++] = roundLine.Theta;
            instanceDataParameter.SetValue(translationData);

            if (techniqueName == null)
                effect.CurrentTechnique = effect.Techniques["AlphaGradient"];
            else
                effect.CurrentTechnique = effect.Techniques[techniqueName];
            effect.Begin();
            EffectPass pass = effect.CurrentTechnique.Passes[0];

            pass.Begin();

            int numInstancesThisDraw = 1;
            device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, numVertices, 0, numPrimitivesPerInstance * numInstancesThisDraw);
            NumLinesDrawn += numInstancesThisDraw;

            pass.End();

            effect.End();

            device.VertexDeclaration = oldVertexDeclaration;
            device.RenderState.CullMode = CullMode.None;
        }
        /// <summary>
        /// Given a bunch of lines (lineList) and a disc that wants to move from currentPos
        /// to proposedPos, handle intersections and wall sliding and set finalPos to the 
        /// position that the disc should move to.
        /// </summary>
        public void CollideAndSlide(List<RoundLine> lineList, Vector2 currentPos, Vector2 proposedPos, float lineRadius, float discRadius, out Vector2 finalPos)
        {
            Vector2 oldPos = currentPos;
            Vector2 oldTarget = proposedPos;
            bool pastFirstSlide = false;

            // Keep looping until there's no further desire to move somewhere else.
            while (Vector2.DistanceSquared(oldPos, oldTarget) > 0.001f * 0.001f)
            {
                // oldPos should be safe (no intersection with anything in lineList)
                Debug.Assert(MinDistanceSquaredDeviation(lineList, oldPos, lineRadius, discRadius) >= 0);

                // Find minimum "t" at which we collide with a line
                float minT = 1.0f; // Parametric "t" of the closest collision
                RoundLine minTLine = null; // The line which causes closest collision
                foreach (RoundLine line in lineList)
                {
                    float tMinThisLine;
                    float minDist = lineRadius + discRadius;
                    float minDist2 = minDist * minDist;
                    float curDist2 = line.DistanceSquaredPointToVirtualLine(oldPos);
                    Debug.Assert(curDist2 - minDist2 >= 0);

                    line.FindFirstIntersection(oldPos, oldTarget, minDist, out tMinThisLine);
                    if (tMinThisLine >= 0 && tMinThisLine <= 1)
                    {
                        // We can move tMinThisLine toward the line, before intersecting it -- but
                        // we might intersect other lines first, so keep looking for
                        // smaller tMinThisLine values on other lines

                        // But first, refine tMinThisLine (if needed) until it satisfies the distance test
                        Vector2 newPos = new Vector2(MathHelper.Lerp(oldPos.X, oldTarget.X, tMinThisLine),
                                                     MathHelper.Lerp(oldPos.Y, oldTarget.Y, tMinThisLine));
                        if (line.DistanceSquaredPointToVirtualLine(newPos) - minDist2 < 0)
                        {
                            float ta = 0;
                            float tb = tMinThisLine;
                            for (int iterRefine = 0; iterRefine < 10; iterRefine++)
                            {
                                float tc = (ta + tb) / 2;
                                Vector2 newPosC = new Vector2(MathHelper.Lerp(oldPos.X, oldTarget.X, tc),
                                                              MathHelper.Lerp(oldPos.Y, oldTarget.Y, tc));
                                float newDistC = line.DistanceSquaredPointToVirtualLine(newPosC);
                                if (newDistC - minDist2 < 0)
                                    tb = tc;
                                else
                                    ta = tc;
                            }
                            tMinThisLine = ta;
                        }

                        // Remember this "t" and the line that caused it, if it's the closest so far
                        if (tMinThisLine < minT)
                        {
                            minT = tMinThisLine;
                            minTLine = line;
                        }
                    }
                    else
                    {
                        // This line has no issue with the disc moving to oldTarget...or does it?
                        // Due to floating point variances, we have to double-check and pick a new "t"
                        // if oldTarget is actually too close to this line
                        float newDist = line.DistanceSquaredPointToVirtualLine(oldTarget);
                        if (newDist - minDist2 < 0)
                        {
                            // Find a "t" that is as large as possible while avoiding collision
                            float ta = 0;
                            float tb = 1;
                            for (int i = 0; i < 10; i++)
                            {
                                float tc = (ta + tb) / 2;
                                Vector2 ptC = new Vector2(MathHelper.Lerp(oldPos.X, oldTarget.X, tc),
                                                          MathHelper.Lerp(oldPos.Y, oldTarget.Y, tc));
                                float distC = line.DistanceSquaredPointToVirtualLine(ptC);
                                if (distC - minDist2 < 0)
                                    tb = tc;
                                else
                                    ta = tc;
                            }

                            if (ta < minT)
                            {
                                minT = ta;
                                minTLine = line;
                            }
                        }
                    }
                }

                // At this point, we've looped through all lines and found the minimum "t" value and its line

                if (minTLine == null)
                {
                    // No intersections were found, so move straight to the target
                    Debug.Assert(MinDistanceSquaredDeviation(lineList, oldTarget, lineRadius, discRadius) >= 0);
                    oldPos = oldTarget; // no further motion required
                }
                else
                {
                    // Collide and slide against minTLine
                    Vector2 newPos = new Vector2(MathHelper.Lerp(oldPos.X, oldTarget.X, minT),
                                                 MathHelper.Lerp(oldPos.Y, oldTarget.Y, minT));
                    Vector2 newTarget;

                    float minDist2 = (lineRadius + discRadius) * (lineRadius + discRadius);

                    // Refine minT / newPos til it passes the distance test
                    float minDistDeviation = MinDistanceSquaredDeviation(lineList, newPos, lineRadius, discRadius);
                    if (minDistDeviation < 0)
                    {
                        float ta = 0;
                        float tb = minT;
                        for (int i = 0; i < 10; i++)
                        {
                            float tc = (ta + tb) / 2;
                            Vector2 ptC = new Vector2(MathHelper.Lerp(oldPos.X, oldTarget.X, tc),
                                                      MathHelper.Lerp(oldPos.Y, oldTarget.Y, tc));
                            if (MinDistanceSquaredDeviation(lineList, ptC, lineRadius, discRadius) < 0)
                                tb = tc;
                            else
                                ta = tc;
                        }
                        minT = ta;
                        newPos = new Vector2(MathHelper.Lerp(oldPos.X, oldTarget.X, minT),
                                             MathHelper.Lerp(oldPos.Y, oldTarget.Y, minT));
                    }
                    Debug.Assert(MinDistanceSquaredDeviation(lineList, newPos, lineRadius, discRadius) >= 0);

                    // This is a bit of a hack to avoid "jiggling" when the disc is pressed
                    // against two walls that are at an obtuse angle.  Perhaps the real fix
                    // is to project the new slide vector against the original motion vector?
                    // In practice, we only ever need to slide once -- this fixes the issue.
                    bool doSlide = true;
                    if (pastFirstSlide)
                    {
                        newTarget = newPos;
                        doSlide = false;
                    }
                    else
                    {
                        pastFirstSlide = true;
                    }

                    if (doSlide)
                    {
                        Vector2 closestP;
                        float d2 = minTLine.DistanceSquaredPointToVirtualLine(newPos, out closestP);
                        RoundLine connectionLine = new RoundLine(newPos, closestP);
                        Vector2 lineNormal = (newPos - closestP);
                        lineNormal.Normalize();

                        // create a normal to the above line
                        // (which would thus be a tangent to minTLine)
                        float theta = connectionLine.Theta;
                        theta += MathHelper.PiOver2;
                        Vector2 newPoint = new Vector2(newPos.X + (float)Math.Cos(theta), newPos.Y + (float)Math.Sin(theta));

                        // Project the post-intersection line onto the above line, to provide "wall sliding" effect
                        // v1 dot v2 = |v2| * (projection of v1 onto v2), and |v2| is 1
                        Vector2 v1 = oldTarget - newPos;
                        Vector2 v2 = newPoint - newPos;
                        float dotprod = Vector2.Dot(v1, v2);

                        newTarget = newPos + dotprod * v2;
                        // newTarget should not be too close to minTLine
                        float newTargetDist = minTLine.DistanceSquaredPointToVirtualLine(newTarget);
                        if (newTargetDist - minDist2 < 0)
                        {
                            float shiftAmtA = 0; // not enough
                            float shiftAmtB = -(newTargetDist - minDist2) + 0.0001f; // too much
                            for (int i = 0; i < 10; i++)
                            {
                                float shiftAmtC = (shiftAmtA + shiftAmtB) / 2.0f;
                                Vector2 newTargetTest = newTarget + (shiftAmtC * lineNormal);
                                float newTargetTestDist = minTLine.DistanceSquaredPointToVirtualLine(newTargetTest);
                                if (newTargetTestDist - minDist2 >= 0)
                                    shiftAmtB = shiftAmtC;
                                else
                                    shiftAmtA = shiftAmtC;
                            }
                            newTarget += shiftAmtB * lineNormal;
                        }
                    }
                    else
                    {
                        newTarget = newPos; // No slide
                    }

                    // Get ready to loop around and see if we can move from newPos to newTarget
                    // without colliding with anything
                    oldPos = newPos;
                    oldTarget = newTarget;

                    Debug.Assert(minTLine.DistanceSquaredPointToVirtualLine(newPos) - minDist2 >= 0);
                }
            }

            // oldTarget == oldPos (or is very close), so no further moving/sliding is needed.
            finalPos = oldPos;
            Debug.Assert(MinDistanceSquaredDeviation(lineList, finalPos, lineRadius, discRadius) >= 0);
        }
Example #6
0
        public override void OnDraw(GraphicsDevice graphicsDevice, VikingXNA.Scene scene, BasicEffect basicEffect)
        {
            if (this.oldMouse == null)
                return;

            WebAnnotation.ViewModel.SectionLocationsViewModel sectionAnnotations = AnnotationOverlay.GetAnnotationsForSection(OriginObj.Section);
            if (sectionAnnotations == null)
                return;

            GridVector2 OriginPosition = OriginObj.VolumePosition;

            Vector3 target;
            if (NearestTarget != null)
            {
                //Snap the line to a nearby target if it exists
                GridVector2 targetPos = NearestTarget.VolumePosition;

                /*bool success = sectionAnnotations.TryGetPositionForLocation(NearestTarget, out targetPos);
                if (!success)
                    return;
                */

                target = new Vector3((float)targetPos.X, (float)targetPos.Y, 0f);
            }
            else
            {
                //Otherwise use the old mouse position
                target = new Vector3((float)this.oldWorldPosition.X, (float)oldWorldPosition.Y, 0f);
            }

            Color lineColor = new Color(Color.Black.R,
                                        Color.Black.G,
                                        Color.Black.B,
                                        0.5f);

            if (NearestTarget != null)
            {
                Structure TargetStruct = NearestTarget.Parent;
                if (TargetStruct != null)
                {
                    //If they are the same structure on different sections use the color for a location link, otherwise white
                    if (TargetStruct == OriginObj.Parent)
                    {
                        if (NearestTarget.Z != OriginObj.Z)
                        {
                            //Make sure the locations aren't already linked
                            bool ValidTarget = true;
                            foreach (long linkID in OriginObj.Links)
                            {
                                if (linkID == NearestTarget.ID)
                                {
                                    ValidTarget = false;
                                    break;
                                }
                            }

                            if (ValidTarget)
                            {
                                StructureType type = OriginObj.Parent.Type;
                                //If you don't cast to byte the wrong constructor is used and the alpha value is wrong
                                lineColor = new Microsoft.Xna.Framework.Color((byte)(255 - type.Color.R),
                                    (byte)(255 - type.Color.G),
                                    (byte)(255 - type.Color.B),
                                    (byte)128);
                            }
                        }
                    }
                    else
                    {
                        lineColor = new Color(Color.White.R,
                                              Color.White.G,
                                              Color.White.B,
                                              0.5f);
                    }
                }
            }

            RoundLine lineToParent = new RoundLine((float)OriginPosition.X,
                                                   (float)OriginPosition.Y,
                                                   (float)target.X,
                                                   (float)target.Y);

            Parent.LineManager.Draw(lineToParent,
                                    (float)(OriginObj.Radius / 6.0),
                                    lineColor,
                                    basicEffect.View * basicEffect.Projection,
                                    1,
                                    null);

            base.OnDraw(graphicsDevice, scene, basicEffect);
        }