Beispiel #1
0
        protected virtual void updateMatrixes()
        {
            if (!_areMatrixesDirty)
            {
                return;
            }

            Matrix2D tempMat;

            _transformMatrix = Matrix2D.createTranslation(-entity.transform.position.X, -entity.transform.position.Y);               // position

            if (_zoom != 1f)
            {
                Matrix2D.createScale(_zoom, _zoom, out tempMat);                   // scale ->
                Matrix2D.multiply(ref _transformMatrix, ref tempMat, out _transformMatrix);
            }

            if (entity.transform.rotation != 0f)
            {
                Matrix2D.createRotation(entity.transform.rotation, out tempMat);                   // rotation
                Matrix2D.multiply(ref _transformMatrix, ref tempMat, out _transformMatrix);
            }

            Matrix2D.createTranslation((int)_origin.X, (int)_origin.Y, out tempMat);               // translate -origin
            Matrix2D.multiply(ref _transformMatrix, ref tempMat, out _transformMatrix);

            // calculate our inverse as well
            Matrix2D.invert(ref _transformMatrix, out _inverseTransformMatrix);

            // whenever the matrix changes the bounds are then invalid
            _areBoundsDirty   = true;
            _areMatrixesDirty = false;
        }
Beispiel #2
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);
            }
        }
Beispiel #3
0
        void updateTransform()
        {
            if (hierarchyDirty != DirtyType.Clean)
            {
                if (parent != null)
                {
                    parent.updateTransform();
                }

                if (_localDirty)
                {
                    if (_localPositionDirty)
                    {
                        Matrix2D.createTranslation(_localPosition.X, _localPosition.Y, out _translationMatrix);
                        _localPositionDirty = false;
                    }

                    if (_localRotationDirty)
                    {
                        Matrix2D.createRotation(_localRotation, out _rotationMatrix);
                        _localRotationDirty = false;
                    }

                    if (_localScaleDirty)
                    {
                        Matrix2D.createScale(_localScale.X, _localScale.Y, out _scaleMatrix);
                        _localScaleDirty = false;
                    }

                    Matrix2D.multiply(ref _scaleMatrix, ref _rotationMatrix, out _localTransform);
                    Matrix2D.multiply(ref _localTransform, ref _translationMatrix, out _localTransform);

                    if (parent == null)
                    {
                        _worldTransform    = _localTransform;
                        _rotation          = _localRotation;
                        _scale             = _localScale;
                        _worldInverseDirty = true;
                    }

                    _localDirty = false;
                }

                if (parent != null)
                {
                    Matrix2D.multiply(ref _localTransform, ref parent._worldTransform, out _worldTransform);

                    _rotation          = _localRotation + parent._rotation;
                    _scale             = parent._scale * _localScale;
                    _worldInverseDirty = true;
                }

                _worldToLocalDirty = true;
                _positionDirty     = true;
                hierarchyDirty     = DirtyType.Clean;
            }
        }
Beispiel #4
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;
            }
        }
Beispiel #5
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;
            }
        }