예제 #1
0
        public void calculateBounds(
            Vector2 parentPosition,
            Vector2 position,
            Vector2 origin,
            Vector2 scale,
            float rotation,
            float width,
            float height)
        {
            if (rotation == 0f)
            {
                x           = parentPosition.X + position.X - origin.X * scale.X;
                y           = parentPosition.Y + position.Y - origin.Y * scale.Y;
                this.width  = width * scale.X;
                this.height = height * scale.Y;
            }
            else
            {
                // special care for rotated bounds. we need to find our absolute min/max values and create the bounds from that
                var worldPosX = parentPosition.X + position.X;
                var worldPosY = parentPosition.Y + position.Y;

                // set the reference point to world reference taking origin into account
                Matrix2D.createTranslation(-worldPosX - origin.X, -worldPosY - origin.Y, out _transformMat);
                Matrix2D.createScale(scale.X, scale.Y, out _tempMat);           // scale ->
                Matrix2D.multiply(ref _transformMat, ref _tempMat, out _transformMat);
                Matrix2D.createRotation(rotation, out _tempMat);                // rotate ->
                Matrix2D.multiply(ref _transformMat, ref _tempMat, out _transformMat);
                Matrix2D.createTranslation(worldPosX, worldPosY, out _tempMat); // translate back
                Matrix2D.multiply(ref _transformMat, ref _tempMat, out _transformMat);

                // TODO: this is a bit silly. we can just leave the worldPos translation in the Matrix and avoid this
                // get all four corners in world space
                var topLeft     = new Vector2(worldPosX, worldPosY);
                var topRight    = new Vector2(worldPosX + width, worldPosY);
                var bottomLeft  = new Vector2(worldPosX, worldPosY + height);
                var bottomRight = new Vector2(worldPosX + width, worldPosY + height);

                // transform the corners into our work space
                Vector2Ext.transform(ref topLeft, ref _transformMat, out topLeft);
                Vector2Ext.transform(ref topRight, ref _transformMat, out topRight);
                Vector2Ext.transform(ref bottomLeft, ref _transformMat, out bottomLeft);
                Vector2Ext.transform(ref bottomRight, ref _transformMat, out bottomRight);

                // find the min and max values so we can concoct our bounding box
                var minX = Mathf.minOf(topLeft.X, bottomRight.X, topRight.X, bottomLeft.X);
                var maxX = Mathf.maxOf(topLeft.X, bottomRight.X, topRight.X, bottomLeft.X);
                var minY = Mathf.minOf(topLeft.Y, bottomRight.Y, topRight.Y, bottomLeft.Y);
                var maxY = Mathf.maxOf(topLeft.Y, bottomRight.Y, topRight.Y, bottomLeft.Y);

                location    = new Vector2(minX, minY);
                this.width  = maxX - minX;
                this.height = maxY - minY;
            }
        }
예제 #2
0
        public void drawArrow(Vector2 start, Vector2 end, float length, float width, bool drawStartIndicator, Color color)
        {
            // Draw connection segment between start- and end-point
            //drawLine( start, end, color );

            // Precalculate halfwidth
            var halfWidth = width / 2;

            // Create directional reference
            Vector2 rotation = (start - end);

            rotation.Normalize();

            // Calculate angle of directional vector
            float angle = (float)Math.Atan2(rotation.X, -rotation.Y);
            // Create matrix for rotation
            Matrix2D rotMatrix = Matrix2D.CreateRotationZ(angle);
            // Create translation matrix for end-point
            Matrix2D endMatrix = Matrix2D.CreateTranslation(end.X, end.Y, 0);

            // Setup arrow end shape
            Vector2[] verts = new Vector2[3];
            verts[0] = new Vector2(0, 0);
            verts[1] = new Vector2(-halfWidth, -length);
            verts[2] = new Vector2(halfWidth, -length);

            // Rotate end shape
            Vector2Ext.Transform(verts, ref rotMatrix, verts);
            // Translate end shape
            Vector2Ext.Transform(verts, ref endMatrix, verts);

            // Draw arrow end shape
            drawPolygon(verts, 3, color);

            if (drawStartIndicator)
            {
                // Create translation matrix for start
                Matrix2D startMatrix = Matrix2D.CreateTranslation(start.X, start.Y, 0);
                // Setup arrow start shape
                Vector2[] baseVerts = new Vector2[4];
                baseVerts[0] = new Vector2(-halfWidth, length / 4);
                baseVerts[1] = new Vector2(halfWidth, length / 4);
                baseVerts[2] = new Vector2(halfWidth, 0);
                baseVerts[3] = new Vector2(-halfWidth, 0);

                // Rotate start shape
                Vector2Ext.Transform(baseVerts, ref rotMatrix, baseVerts);
                // Translate start shape
                Vector2Ext.Transform(baseVerts, ref startMatrix, baseVerts);
                // Draw start shape
                drawPolygon(baseVerts, 4, color);
            }
        }
예제 #3
0
        public static void CalculateBounds(ref Rectangle rect, Vector2 parentPosition, Vector2 position, Vector2 origin,
                                           Vector2 scale, float rotation, float width, float height)
        {
            if (rotation == 0f)
            {
                rect.X      = (int)(parentPosition.X + position.X - origin.X * scale.X);
                rect.Y      = (int)(parentPosition.Y + position.Y - origin.Y * scale.Y);
                rect.Width  = (int)(width * scale.X);
                rect.Height = (int)(height * scale.Y);
            }
            else
            {
                // special care for rotated bounds. we need to find our absolute min/max values and create the bounds from that
                var worldPosX = parentPosition.X + position.X;
                var worldPosY = parentPosition.Y + position.Y;

                Matrix2D tempMat;

                // set the reference point to world reference taking origin into account
                var transformMatrix = Matrix2D.CreateTranslation(-worldPosX - origin.X, -worldPosY - origin.Y);
                Matrix2D.CreateScale(scale.X, scale.Y, out tempMat);            // scale ->
                Matrix2D.Multiply(ref transformMatrix, ref tempMat, out transformMatrix);
                Matrix2D.CreateRotation(rotation, out tempMat);                 // rotate ->
                Matrix2D.Multiply(ref transformMatrix, ref tempMat, out transformMatrix);
                Matrix2D.CreateTranslation(worldPosX, worldPosY, out tempMat);  // translate back
                Matrix2D.Multiply(ref transformMatrix, ref tempMat, out transformMatrix);

                // TODO: this is a bit silly. we can just leave the worldPos translation in the Matrix and avoid this
                // get all four corners in world space
                var topLeft     = new Vector2(worldPosX, worldPosY);
                var topRight    = new Vector2(worldPosX + width, worldPosY);
                var bottomLeft  = new Vector2(worldPosX, worldPosY + height);
                var bottomRight = new Vector2(worldPosX + width, worldPosY + height);

                // transform the corners into our work space
                Vector2Ext.Transform(ref topLeft, ref transformMatrix, out topLeft);
                Vector2Ext.Transform(ref topRight, ref transformMatrix, out topRight);
                Vector2Ext.Transform(ref bottomLeft, ref transformMatrix, out bottomLeft);
                Vector2Ext.Transform(ref bottomRight, ref transformMatrix, out bottomRight);

                // find the min and max values so we can concoct our bounding box
                var minX = (int)Mathf.MinOf(topLeft.X, bottomRight.X, topRight.X, bottomLeft.X);
                var maxX = (int)Mathf.MaxOf(topLeft.X, bottomRight.X, topRight.X, bottomLeft.X);
                var minY = (int)Mathf.MinOf(topLeft.Y, bottomRight.Y, topRight.Y, bottomLeft.Y);
                var maxY = (int)Mathf.MaxOf(topLeft.Y, bottomRight.Y, topRight.Y, bottomLeft.Y);

                rect.Location = new Point(minX, minY);
                rect.Width    = (int)(maxX - minX);
                rect.Height   = (int)(maxY - minY);
            }
        }
예제 #4
0
        public static void DrawHollowRect(this Batcher batcher, float x, float y, float width, float height,
                                          Color color, float thickness = 1)
        {
            var tl = Vector2Ext.Round(new Vector2(x, y));
            var tr = Vector2Ext.Round(new Vector2(x + width, y));
            var br = Vector2Ext.Round(new Vector2(x + width, y + height));
            var bl = Vector2Ext.Round(new Vector2(x, y + height));

            batcher.SetIgnoreRoundingDestinations(true);
            batcher.DrawLine(tl, tr, color, thickness);
            batcher.DrawLine(tr, br, color, thickness);
            batcher.DrawLine(br, bl, color, thickness);
            batcher.DrawLine(bl, tl, color, thickness);
            batcher.SetIgnoreRoundingDestinations(false);
        }
예제 #5
0
            public void setFusedData(bool shouldFuseBottom, ref Segment segment)
            {
                // store the angle off for later. For extreme angles we add extra verts to smooth the joint
                angle = Vector2Ext.angle(segment.point.position - point.position, nextPoint.position - point.position);
                this.shouldFuseBottom = shouldFuseBottom;

                if (shouldFuseBottom)
                {
                    hasFusedPoint = ShapeCollisions.lineToLine(segment.bl, segment.br, bl, br, out fusedPoint);
                }
                else
                {
                    hasFusedPoint = ShapeCollisions.lineToLine(segment.tl, segment.tr, tl, tr, out fusedPoint);
                }
            }
예제 #6
0
            public void SetFusedData(bool shouldFuseBottom, ref Segment segment)
            {
                // store the angle off for later. For extreme angles we add extra verts to smooth the joint
                Angle = Vector2Ext.Angle(segment.Point.Position - Point.Position, NextPoint.Position - Point.Position);
                this.ShouldFuseBottom = shouldFuseBottom;

                if (shouldFuseBottom)
                {
                    HasFusedPoint = ShapeCollisions.LineToLine(segment.Bl, segment.Br, Bl, Br, out FusedPoint);
                }
                else
                {
                    HasFusedPoint = ShapeCollisions.LineToLine(segment.Tl, segment.Tr, Tl, Tr, out FusedPoint);
                }
            }
예제 #7
0
        void patchJaggedJoint(ref Segment segment, ref int vertIndex)
        {
            Vector2 intersection;

            if (segment.shouldFuseBottom)
            {
                if (Vector2Ext.getRayIntersection(
                        segment.tl,
                        segment.tr,
                        _lastSegment.tl,
                        _lastSegment.tr,
                        out intersection))
                {
                    addVert(vertIndex++, intersection, new Vector2(1, 1), segment.point.color);

                    _indices.add((short)vertIndex);
                    _indices.add((short)(vertIndex + 4));
                    _indices.add((short)(vertIndex - 1));

                    _indices.add((short)(vertIndex - 1));
                    _indices.add((short)(vertIndex + 4));
                    _indices.add((short)(vertIndex - 5));
                }
            }
            else
            {
                if (Vector2Ext.getRayIntersection(
                        segment.bl,
                        segment.br,
                        _lastSegment.bl,
                        _lastSegment.br,
                        out intersection))
                {
                    var firstSegmentOffset = vertIndex == 5 ? 1 : 0;
                    addVert(vertIndex++, intersection, new Vector2(1, 0), segment.point.color);

                    _indices.add((short)(vertIndex + 4));
                    _indices.add((short)(vertIndex + 3));
                    _indices.add((short)(vertIndex - 1));

                    _indices.add((short)(vertIndex - 3 + firstSegmentOffset));
                    _indices.add((short)(vertIndex + 4));
                    _indices.add((short)(vertIndex - 1));
                }
            }
        }
예제 #8
0
        /// <summary>
        /// sets the position of the transform relative to the parent transform. If the transform has no parent, it is the same
        /// as Transform.position
        /// </summary>
        /// <returns>The local position.</returns>
        /// <param name="localPosition">Local position.</param>
        public Transform setLocalPosition(Vector2 localPosition)
        {
            if (shouldRoundPosition)
            {
                Vector2Ext.round(ref localPosition);
            }

            if (localPosition == _localPosition)
            {
                return(this);
            }

            _localPosition = localPosition;
            _localDirty    = _positionDirty = _localPositionDirty = _localRotationDirty = _localScaleDirty = true;
            setDirty(DirtyType.PositionDirty);

            return(this);
        }
예제 #9
0
        public static void drawCircle(this Batcher batcher, Vector2 position, float radius, Color color, float thickness = 1f, int resolution = 12)
        {
            var last  = Vector2.UnitX * radius;
            var lastP = Vector2Ext.perpendicular(last);

            for (int i = 1; i <= resolution; i++)
            {
                var at  = Mathf.angleToVector(i * MathHelper.PiOver2 / resolution, radius);
                var atP = Vector2Ext.perpendicular(at);

                drawLine(batcher, position + last, position + at, color, thickness);
                drawLine(batcher, position - last, position - at, color, thickness);
                drawLine(batcher, position + lastP, position + atP, color, thickness);
                drawLine(batcher, position - lastP, position - atP, color, thickness);

                last  = at;
                lastP = atP;
            }
        }
예제 #10
0
        public static void DrawCircle(this SpriteBatch spriteBatch, System.Numerics.Vector2 position, float radius, Color color,
                                      float thickness = 1f, int resolution = 12)
        {
            var last  = System.Numerics.Vector2.UnitX * radius;
            var lastP = Vector2Ext.Perpendicular(last);

            for (int i = 1; i <= resolution; i++)
            {
                var at  = Mathf.AngleToVector(i * MathHelper.PiOver2 / resolution, radius);
                var atP = Vector2Ext.Perpendicular(at);

                DrawLine(spriteBatch, position + last, position + at, color, thickness);
                DrawLine(spriteBatch, position - last, position - at, color, thickness);
                DrawLine(spriteBatch, position + lastP, position + atP, color, thickness);
                DrawLine(spriteBatch, position - lastP, position - atP, color, thickness);

                last  = at;
                lastP = atP;
            }
        }
예제 #11
0
        public static void DrawCircle(this Batcher batcher, Vector2 position, float radius, Color color, float thickness = 1f, int resolution = 12)
        {
            var last  = Vector2.UnitX * radius;
            var lastP = Vector2Ext.Perpendicular(last);

            batcher.SetIgnoreRoundingDestinations(true);
            for (int i = 1; i <= resolution; i++)
            {
                var at  = Mathf.AngleToVector(i * MathHelper.PiOver2 / resolution, radius);
                var atP = Vector2Ext.Perpendicular(at);

                DrawLine(batcher, position + last, position + at, color, thickness);
                DrawLine(batcher, position - last, position - at, color, thickness);
                DrawLine(batcher, position + lastP, position + atP, color, thickness);
                DrawLine(batcher, position - lastP, position - atP, color, thickness);

                last  = at;
                lastP = atP;
            }
            batcher.SetIgnoreRoundingDestinations(false);
        }
예제 #12
0
        void PatchJaggedJoint(ref Segment segment, ref int vertIndex)
        {
            Vector2 intersection;

            if (segment.ShouldFuseBottom)
            {
                if (Vector2Ext.GetRayIntersection(segment.Tl, segment.Tr, _lastSegment.Tl, _lastSegment.Tr,
                                                  out intersection))
                {
                    AddVert(vertIndex++, intersection, new Vector2(1, 1), segment.Point.Color);

                    _indices.Add((short)vertIndex);
                    _indices.Add((short)(vertIndex + 4));
                    _indices.Add((short)(vertIndex - 1));

                    _indices.Add((short)(vertIndex - 1));
                    _indices.Add((short)(vertIndex + 4));
                    _indices.Add((short)(vertIndex - 5));
                }
            }
            else
            {
                if (Vector2Ext.GetRayIntersection(segment.Bl, segment.Br, _lastSegment.Bl, _lastSegment.Br,
                                                  out intersection))
                {
                    var firstSegmentOffset = vertIndex == 5 ? 1 : 0;
                    AddVert(vertIndex++, intersection, new Vector2(1, 0), segment.Point.Color);

                    _indices.Add((short)(vertIndex + 4));
                    _indices.Add((short)(vertIndex + 3));
                    _indices.Add((short)(vertIndex - 1));

                    _indices.Add((short)(vertIndex - 3 + firstSegmentOffset));
                    _indices.Add((short)(vertIndex + 4));
                    _indices.Add((short)(vertIndex - 1));
                }
            }
        }
        public static bool testPointTriangle(Vector2 point, Vector2 a, Vector2 b, Vector2 c)
        {
            // if point to the right of AB then outside triangle
            if (Vector2Ext.cross(point - a, b - a) < 0f)
            {
                return(false);
            }

            // if point to the right of BC then outside of triangle
            if (Vector2Ext.cross(point - b, c - b) < 0f)
            {
                return(false);
            }

            // if point to the right of ca then outside of triangle
            if (Vector2Ext.cross(point - c, a - c) < 0f)
            {
                return(false);
            }

            // point is in or on triangle
            return(true);
        }
예제 #14
0
 /// <summary>
 /// converts a point from screen coordinates to world
 /// </summary>
 /// <returns>The to world point.</returns>
 /// <param name="screenPosition">Screen position.</param>
 public Vector2 screenToWorldPoint(Vector2 screenPosition)
 {
     updateMatrixes();
     Vector2Ext.transform(ref screenPosition, ref _inverseTransformMatrix, out screenPosition);
     return(screenPosition);
 }
예제 #15
0
 /// <summary>
 /// converts a point from world coordinates to screen
 /// </summary>
 /// <returns>The to screen point.</returns>
 /// <param name="worldPosition">World position.</param>
 public Vector2 worldToScreenPoint(Vector2 worldPosition)
 {
     updateMatrixes();
     Vector2Ext.transform(ref worldPosition, ref _transformMatrix, out worldPosition);
     return(worldPosition);
 }
예제 #16
0
 public override void OnAddedToEntity()
 {
     OriginNormalized = Vector2Ext.HalfVector();
 }
예제 #17
0
 public static bool isTriangleCCW(Vector2 a, Vector2 b, Vector2 c)
 {
     return(Vector2Ext.cross(b - a, c - b) < 0);
 }
예제 #18
0
        /// <summary>
        /// compiles the text into raw verts/texture coordinates. This method must be called anytime text or any other properties are
        /// changed.
        /// </summary>
        public void compile()
        {
            _charDetails = new CharDetails[_text.Length];
            Character currentCharacter = null;
            var       effects          = (byte)SpriteEffects.None;

            var _transformationMatrix  = Matrix2D.identity;
            var requiresTransformation = rotation != 0f || _scale != Vector2.One;

            if (requiresTransformation)
            {
                Matrix2D temp;
                Matrix2D.createTranslation(-_origin.X, -_origin.Y, out _transformationMatrix);
                Matrix2D.createScale(_scale.X, _scale.Y, out temp);
                Matrix2D.multiply(ref _transformationMatrix, ref temp, out _transformationMatrix);
                Matrix2D.createRotation(rotation, out temp);
                Matrix2D.multiply(ref _transformationMatrix, ref temp, out _transformationMatrix);
                Matrix2D.createTranslation(position.X, position.Y, out temp);
                Matrix2D.multiply(ref _transformationMatrix, ref temp, out _transformationMatrix);
            }

            var offset = requiresTransformation ? Vector2.Zero : position - _origin;

            for (var i = 0; i < _text.Length; ++i)
            {
                _charDetails[i].initialize();
                _charDetails[i].color = _color;

                var c = _text[i];
                if (c == '\n')
                {
                    offset.X         = requiresTransformation ? 0f : position.X - _origin.X;
                    offset.Y        += _font.lineHeight;
                    currentCharacter = null;
                    continue;
                }

                if (currentCharacter != null)
                {
                    offset.X += _font.spacing.X + currentCharacter.xAdvance;
                }

                currentCharacter = _font[c];
                var p = offset;
                p.X += currentCharacter.offset.X;
                p.Y += currentCharacter.offset.Y;

                // transform our point if we need to
                if (requiresTransformation)
                {
                    Vector2Ext.transform(ref p, ref _transformationMatrix, out p);
                }

                var destination = new Vector4(p.X, p.Y, currentCharacter.bounds.Width * _scale.X, currentCharacter.bounds.Height * _scale.Y);
                _charDetails[i].texture = _font.textures[_font[currentCharacter.character].texturePage];
                //_charDetails[i].texture = currentCharacter.subtexture.texture2D;


                // Batcher calculations
                var   sourceRectangle = currentCharacter.bounds;
                float sourceX, sourceY, sourceW, sourceH;
                var   destW = destination.Z;
                var   destH = destination.W;

                // calculate uvs
                var inverseTexW = 1.0f / (float)currentCharacter.bounds.Width;
                var inverseTexH = 1.0f / (float)currentCharacter.bounds.Height;

                sourceX = sourceRectangle.X * inverseTexW;
                sourceY = sourceRectangle.Y * inverseTexH;
                sourceW = Math.Max(sourceRectangle.Width, float.Epsilon) * inverseTexW;
                sourceH = Math.Max(sourceRectangle.Height, float.Epsilon) * inverseTexH;

                // Rotation Calculations
                float rotationMatrix1X;
                float rotationMatrix1Y;
                float rotationMatrix2X;
                float rotationMatrix2Y;
                if (!Mathf.withinEpsilon(rotation, 0.0f))
                {
                    var sin = Mathf.sin(rotation);
                    var cos = Mathf.cos(rotation);
                    rotationMatrix1X = cos;
                    rotationMatrix1Y = sin;
                    rotationMatrix2X = -sin;
                    rotationMatrix2Y = cos;
                }
                else
                {
                    rotationMatrix1X = 1.0f;
                    rotationMatrix1Y = 0.0f;
                    rotationMatrix2X = 0.0f;
                    rotationMatrix2Y = 1.0f;
                }

                // Calculate vertices, finally.
                // top-left
                _charDetails[i].verts[0].X = rotationMatrix2X + rotationMatrix1X + destination.X - 1;
                _charDetails[i].verts[0].Y = rotationMatrix2Y + rotationMatrix1Y + destination.Y - 1;

                // top-right
                var cornerX = _cornerOffsetX[1] * destW;
                var cornerY = _cornerOffsetY[1] * destH;
                _charDetails[i].verts[1].X = (
                    (rotationMatrix2X * cornerY) +
                    (rotationMatrix1X * cornerX) +
                    destination.X
                    );
                _charDetails[i].verts[1].Y = (
                    (rotationMatrix2Y * cornerY) +
                    (rotationMatrix1Y * cornerX) +
                    destination.Y
                    );

                // bottom-left
                cornerX = _cornerOffsetX[2] * destW;
                cornerY = _cornerOffsetY[2] * destH;
                _charDetails[i].verts[2].X = (
                    (rotationMatrix2X * cornerY) +
                    (rotationMatrix1X * cornerX) +
                    destination.X
                    );
                _charDetails[i].verts[2].Y = (
                    (rotationMatrix2Y * cornerY) +
                    (rotationMatrix1Y * cornerX) +
                    destination.Y
                    );

                // bottom-right
                cornerX = _cornerOffsetX[3] * destW;
                cornerY = _cornerOffsetY[3] * destH;
                _charDetails[i].verts[3].X = (
                    (rotationMatrix2X * cornerY) +
                    (rotationMatrix1X * cornerX) +
                    destination.X
                    );
                _charDetails[i].verts[3].Y = (
                    (rotationMatrix2Y * cornerY) +
                    (rotationMatrix1Y * cornerX) +
                    destination.Y
                    );


                // texture coordintes
                _charDetails[i].texCoords[0].X = (_cornerOffsetX[0 ^ effects] * sourceW) + sourceX;
                _charDetails[i].texCoords[0].Y = (_cornerOffsetY[0 ^ effects] * sourceH) + sourceY;
                _charDetails[i].texCoords[1].X = (_cornerOffsetX[1 ^ effects] * sourceW) + sourceX;
                _charDetails[i].texCoords[1].Y = (_cornerOffsetY[1 ^ effects] * sourceH) + sourceY;
                _charDetails[i].texCoords[2].X = (_cornerOffsetX[2 ^ effects] * sourceW) + sourceX;
                _charDetails[i].texCoords[2].Y = (_cornerOffsetY[2 ^ effects] * sourceH) + sourceY;
                _charDetails[i].texCoords[3].X = (_cornerOffsetX[3 ^ effects] * sourceW) + sourceX;
                _charDetails[i].texCoords[3].Y = (_cornerOffsetY[3 ^ effects] * sourceH) + sourceY;
            }
        }
예제 #19
0
        void calculateVertices()
        {
            if (!_areVertsDirty || _points.length < 2)
            {
                return;
            }

            _areVertsDirty = false;
            _indices.reset();
            _vertices.reset();

            var maxX = float.MinValue;
            var minX = float.MaxValue;
            var maxY = float.MinValue;
            var minY = float.MaxValue;

            if (_useStartEndWidths)
            {
                _maxWidth = System.Math.Max(_startWidth, _endWidth);
            }

            // calculate line length first and simulataneously get our min/max points for the bounds
            var lineLength   = 0f;
            var halfMaxWidth = _maxWidth * 0.5f;

            _points.buffer[0].lengthFromPreviousPoint = 0;
            for (var i = 0; i < _points.length - 1; i++)
            {
                var distance = Vector2.Distance(_points.buffer[i].position, _points.buffer[i + 1].position);
                _points.buffer[i + 1].lengthFromPreviousPoint = distance;
                lineLength += distance;

                maxX = Mathf.maxOf(maxX, _points.buffer[i].position.X + halfMaxWidth, _points.buffer[i + 1].position.X + halfMaxWidth);
                minX = Mathf.minOf(minX, _points.buffer[i].position.X - halfMaxWidth, _points.buffer[i + 1].position.X - halfMaxWidth);
                maxY = Mathf.maxOf(maxY, _points.buffer[i].position.Y + halfMaxWidth, _points.buffer[i + 1].position.Y + halfMaxWidth);
                minY = Mathf.minOf(minY, _points.buffer[i].position.Y - halfMaxWidth, _points.buffer[i + 1].position.Y - halfMaxWidth);
            }

            _bounds.x      = minX;
            _bounds.y      = minY;
            _bounds.width  = maxX - minX;
            _bounds.height = maxY - minY;

            // special case: single segment
            if (_points.length == 2)
            {
                if (_useStartEndWidths)
                {
                    _points.buffer[0].width = _startWidth;
                    _points.buffer[1].width = _endWidth;
                }

                if (_useStartEndColors)
                {
                    _points.buffer[0].color = _startColor;
                    _points.buffer[1].color = _endColor;
                }

                _firstSegment.setPoints(ref _points.buffer[0], ref _points.buffer[1]);
                addSingleSegmentLine(ref _firstSegment, _points.buffer[1].color);
                return;
            }

            var distanceSoFar = 0f;
            var fusedPoint    = Vector2.Zero;
            var vertIndex     = 0;
            var thirdPoint    = new SegmentPoint();

            for (var i = 0; i < _points.length - 1; i++)
            {
                var firstPoint  = _points.buffer[i];
                var secondPoint = _points.buffer[i + 1];

                var hasThirdPoint = _points.length > i + 2;
                if (hasThirdPoint)
                {
                    thirdPoint = _points.buffer[i + 2];
                }

                // we need the distance along the line of both the first and second points. distanceSoFar will always be for the furthest point
                // which is the previous point before adding the current segment distance.
                var firstPointDistance = distanceSoFar;
                distanceSoFar += secondPoint.lengthFromPreviousPoint;

                var firstPointRatio  = firstPointDistance / lineLength;
                var secondPointRatio = distanceSoFar / lineLength;
                var thirdPointRatio  = 0f;
                if (hasThirdPoint)
                {
                    thirdPointRatio = (distanceSoFar + thirdPoint.lengthFromPreviousPoint) / lineLength;
                }

                if (_useStartEndColors)
                {
                    ColorExt.lerp(ref _startColor, ref _endColor, out firstPoint.color, firstPointRatio);
                    ColorExt.lerp(ref _startColor, ref _endColor, out secondPoint.color, secondPointRatio);

                    if (hasThirdPoint)
                    {
                        ColorExt.lerp(ref _startColor, ref _endColor, out thirdPoint.color, thirdPointRatio);
                    }
                }

                if (_useStartEndWidths)
                {
                    firstPoint.width  = Mathf.lerp(_startWidth, _endWidth, firstPointRatio);
                    secondPoint.width = Mathf.lerp(_startWidth, _endWidth, secondPointRatio);

                    if (hasThirdPoint)
                    {
                        thirdPoint.width = Mathf.lerp(_startWidth, _endWidth, thirdPointRatio);
                    }
                }


                if (i == 0)
                {
                    _firstSegment.setPoints(ref firstPoint, ref secondPoint);
                    _secondSegment.setPoints(ref secondPoint, ref thirdPoint);
                }
                else
                {
                    Utils.swap(ref _firstSegment, ref _secondSegment);
                    if (hasThirdPoint)
                    {
                        _secondSegment.setPoints(ref secondPoint, ref thirdPoint);
                    }
                }

                // dont recalculate the fusedPoint for the last segment since there will be no third point to work with
                if (hasThirdPoint)
                {
                    var shouldFuseBottom = Vector2Ext.isTriangleCCW(firstPoint.position, secondPoint.position, thirdPoint.position);
                    _secondSegment.setFusedData(shouldFuseBottom, ref _firstSegment);
                }

                // special care needs to be take with the first segment since it has a different vert count
                if (i == 0)
                {
                    addFirstSegment(ref _firstSegment, ref _secondSegment, ref vertIndex);
                }
                else
                {
                    addSegment(ref _firstSegment, ref vertIndex);
                }

                _lastSegment.cloneFrom(ref _firstSegment);
            }
        }
        /// <summary>
        /// Computes a triangle list that fully covers the area enclosed by the given set of points. If points are not CCW, pass false for
        /// the arePointsCCW parameter
        /// </summary>
        /// <param name="points">A list of points that defines an enclosing path.</param>
        /// <param name="count">The number of points in the path.</param>
        public void triangulate(Vector2[] points, bool arePointsCCW = true)
        {
            var count = points.Length;

            // set up previous and next links to effectively from a double-linked vert list
            initialize(count);

            // loop breaker for polys that are not triangulatable
            var iterations = 0;

            // start at vert 0
            var index = 0;

            // keep removing verts until just a triangle is left
            while (count > 3 && iterations < 500)
            {
                iterations++;
                // test if current vert is an ear
                var isEar = true;

                var a = points[_triPrev[index]];
                var b = points[index];
                var c = points[_triNext[index]];

                // an ear must be convex (here counterclockwise)
                if (Vector2Ext.isTriangleCCW(a, b, c))
                {
                    // loop over all verts not part of the tentative ear
                    var k = _triNext[_triNext[index]];
                    do
                    {
                        // if vert k is inside the ear triangle, then this is not an ear
                        if (testPointTriangle(points[k], a, b, c))
                        {
                            isEar = false;
                            break;
                        }
                        k = _triNext[k];
                    }                   while(k != _triPrev[index]);
                }
                else
                {
                    // the ear triangle is clockwise so points[i] is not an ear
                    isEar = false;
                }

                // if current vert is an ear, delete it and visit the previous vert
                if (isEar)
                {
                    // triangle is an ear
                    triangleIndices.Add(_triPrev[index]);
                    triangleIndices.Add(index);
                    triangleIndices.Add(_triNext[index]);

                    // delete vert by redirecting next and previous links of neighboring verts past it
                    // decrement vertext count
                    _triNext[_triPrev[index]] = _triNext[index];
                    _triPrev[_triNext[index]] = _triPrev[index];
                    count--;

                    // visit the previous vert next
                    index = _triPrev[index];
                }
                else
                {
                    // current vert is not an ear. visit the next vert
                    index = _triNext[index];
                }
            }

            // output the final triangle
            triangleIndices.Add(_triPrev[index]);
            triangleIndices.Add(index);
            triangleIndices.Add(_triNext[index]);

            if (!arePointsCCW)
            {
                triangleIndices.Reverse();
            }
        }
예제 #21
0
        public static Point RoundToPoint(this Vector2 vec)
        {
            var roundedVec = Vector2Ext.Round(vec);

            return(new Point((int)roundedVec.X, (int)roundedVec.Y));
        }
예제 #22
0
        public void drawInto(
            Batcher batcher,
            ref FontCharacterSource text,
            Vector2 position,
            Color color,
            float rotation,
            Vector2 origin,
            Vector2 scale,
            SpriteEffects effect,
            float depth)
        {
            var flipAdjustment = Vector2.Zero;

            var flippedVert = (effect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically;
            var flippedHorz = (effect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally;

            if (flippedVert || flippedHorz)
            {
                Vector2 size;
                measureString(ref text, out size);

                if (flippedHorz)
                {
                    origin.X        *= -1;
                    flipAdjustment.X = -size.X;
                }

                if (flippedVert)
                {
                    origin.Y        *= -1;
                    flipAdjustment.Y = _font.LineSpacing - size.Y;
                }
            }

            // TODO: This looks excessive... i suspect we could do most of this with simple vector math and avoid this much matrix work.
            var requiresTransformation = flippedHorz || flippedVert || rotation != 0f || scale != Vector2.One;

            if (requiresTransformation)
            {
                Matrix2D temp;
                Matrix2D.createTranslation(-origin.X, -origin.Y, out _transformationMatrix);
                Matrix2D.createScale(flippedHorz ? -scale.X : scale.X, flippedVert ? -scale.Y : scale.Y, out temp);
                Matrix2D.multiply(ref _transformationMatrix, ref temp, out _transformationMatrix);
                Matrix2D.createTranslation(flipAdjustment.X, flipAdjustment.Y, out temp);
                Matrix2D.multiply(ref temp, ref _transformationMatrix, out _transformationMatrix);
                Matrix2D.createRotation(rotation, out temp);
                Matrix2D.multiply(ref _transformationMatrix, ref temp, out _transformationMatrix);
                Matrix2D.createTranslation(position.X, position.Y, out temp);
                Matrix2D.multiply(ref _transformationMatrix, ref temp, out _transformationMatrix);
            }

            // Get the default glyph here once.
            SpriteFont.Glyph?defaultGlyph = null;
            if (_font.DefaultCharacter.HasValue)
            {
                defaultGlyph = _glyphs[_font.DefaultCharacter.Value];
            }

            var currentGlyph     = SpriteFont.Glyph.Empty;
            var offset           = requiresTransformation ? Vector2.Zero : position - origin;
            var firstGlyphOfLine = true;

            for (var i = 0; i < text.Length; ++i)
            {
                var c = text[i];

                if (c == '\r')
                {
                    continue;
                }

                if (c == '\n')
                {
                    offset.X         = requiresTransformation ? 0f : position.X - origin.X;
                    offset.Y        += _font.LineSpacing;
                    firstGlyphOfLine = true;
                    continue;
                }

                if (!_glyphs.TryGetValue(c, out currentGlyph))
                {
                    if (!defaultGlyph.HasValue)
                    {
                        throw new ArgumentException("Errors.TextContainsUnresolvableCharacters", "text");
                    }

                    currentGlyph = defaultGlyph.Value;
                }

                // The first character on a line might have a negative left side bearing.
                // In this scenario, SpriteBatch/SpriteFont normally offset the text to the right,
                // so that text does not hang off the left side of its rectangle.
                if (firstGlyphOfLine)
                {
                    offset.X        += Math.Max(currentGlyph.LeftSideBearing, 0);
                    firstGlyphOfLine = false;
                }
                else
                {
                    offset.X += _font.Spacing + currentGlyph.LeftSideBearing;
                }

                var p = offset;

                if (flippedHorz)
                {
                    p.X += currentGlyph.BoundsInTexture.Width;
                }
                p.X += currentGlyph.Cropping.X;

                if (flippedVert)
                {
                    p.Y += currentGlyph.BoundsInTexture.Height - _font.LineSpacing;
                }
                p.Y += currentGlyph.Cropping.Y;

                // transform our point if we need to
                if (requiresTransformation)
                {
                    Vector2Ext.transform(ref p, ref _transformationMatrix, out p);
                }

                var destRect = RectangleExt.fromFloats(
                    p.X,
                    p.Y,
                    currentGlyph.BoundsInTexture.Width * scale.X,
                    currentGlyph.BoundsInTexture.Height * scale.Y);

                batcher.draw(
                    _font.Texture,
                    destRect,
                    currentGlyph.BoundsInTexture,
                    color,
                    rotation,
                    Vector2.Zero,
                    effect,
                    depth);

                offset.X += currentGlyph.Width + currentGlyph.RightSideBearing;
            }
        }
 public override void onAddedToEntity()
 {
     originNormalized = Vector2Ext.halfVector();
 }