Exemple #1
0
        public void DrawSprite(SurfaceSprite surface, int xScreen, int yScreen, bool isHorizontalFlipped, bool isVerticalFlipped, int xSprite = 0, int ySprite = 0, int widthSprite = int.MaxValue, int heightSprite = int.MaxValue)
        {
            if (widthSprite == int.MaxValue)
            {
                widthSprite = surface.Width;
            }

            if (heightSprite == int.MaxValue)
            {
                heightSprite = surface.Height;
            }

            if (this.BoundsClipped.Width <= 0 || this.BoundsClipped.Height <= 0)
            {
                return;
            }

            SurfaceRectangle rectScreen = new SurfaceRectangle();

            int destinationAddress = 0;
            int sourceAddress      = 0;

            // pas de clipping: La destination ne bouge pas (sauf exception des xscreen/yScreen negatif et la source bouge
            if (HaveClip == false)
            {
                // La lecture des pixels commence en négatif (en gros on devrait afficher du transparent)
                // Pour afficher ces pixels qui n'existent pas on compense en poussant la position à l'écran et en diminuant la taille

                if (ySprite < 0)
                {
                    yScreen      += -ySprite;
                    heightSprite += ySprite;
                    ySprite       = 0;
                }

                if (xSprite < 0)
                {
                    xScreen     += -xSprite;
                    widthSprite += xSprite;
                    xSprite      = 0;
                }

                // on genere le rectangle affichable de la source. Il prend en compte son clipping à lui (souvent inutile) mais pas celui de l'ecran.
                var rectSprite = surface.GetVisibleRectangle(xSprite, ySprite, widthSprite, heightSprite, false, false);

                if (rectSprite.isVisible == false)
                {
                    return;
                }

                // on genere le rectangle affichable de l'ecran en prenant la taille de celui du rectangle de la source
                rectScreen = this.GetVisibleRectangle(xScreen, yScreen, rectSprite.width, rectSprite.height, isHorizontalFlipped, isVerticalFlipped);

                if (rectScreen.isVisible == false)
                {
                    return;
                }

                sourceAddress = rectSprite.address;

                // On sort de l'ecran mais le rectangle est visible donc on recalcule l'adresse de départ en ajoutant les lignes perdues
                if (yScreen < 0)
                {
                    if (isVerticalFlipped == false)
                    {
                        sourceAddress += (surface.Width * -yScreen);
                    }
                    else
                    {
                        if (heightSprite > BoundsClipped.Height) // cas ou la taille affichable est plus petite que le sprite et que l'on est flipH
                        {
                            var sourceOffsetY = ((yScreen + heightSprite) - BoundsClipped.Height);

                            if (sourceOffsetY >= 0)
                            {
                                sourceAddress += surface.Width * sourceOffsetY;
                            }
                        }
                        // on avance la source du nombre de pixel caché par le bord de l'ecran
                    }
                }
                else if (yScreen + heightSprite >= BoundsClipped.Height)
                {
                    if (isVerticalFlipped == true)
                    {
                        var sourceOffsetY = ((yScreen + heightSprite) - BoundsClipped.Height);
                        sourceAddress += surface.Width * sourceOffsetY; // on avance la source du nombre de pixel caché par le bord de l'ecran
                    }
                }

                if (xScreen < 0)
                {
                    if (isHorizontalFlipped == false)
                    {
                        sourceAddress += -xScreen; // on avance la source du nombre de pixel caché par le bord de l'ecran
                    }
                    else
                    {
                        if (widthSprite > BoundsClipped.Width) // cas ou la taille affichable est plus petite que le sprite et que l'on est flipH
                        {
                            var sourceOffsetX = ((xScreen + widthSprite) - BoundsClipped.Width);

                            if (sourceOffsetX >= 0)
                            {
                                sourceAddress += sourceOffsetX;
                            }
                        }
                        // on avance la source du nombre de pixel caché par le bord de l'ecran
                    }
                    // en mode flip Horizontal on a pas besoin d'avancer car la source address et la derniere pixel de la ligne
                }
                else if (xScreen + widthSprite >= this.BoundsClipped.Width)
                {
                    if (isHorizontalFlipped == true)
                    {
                        var sourceOffsetX = ((xScreen + widthSprite) - BoundsClipped.Width);
                        sourceAddress += sourceOffsetX; // on avance la source du nombre de pixel caché par le bord de l'ecran
                    }
                }

                destinationAddress = rectScreen.address;
            }

            // ** Gestion du clipping : ici le mouvement se fait du coté de la source et la destination (écran) reste fixe **
            else
            {
                // on genere le rectangle affichable de la source (il prend en compte son clipping à lui (souvent inutile) et le clipping de l'écran mais qui bouge en xscreen et yscreen )

                var sourceClipped = new Rectangle(this.BoundsClipped.X - xScreen + xSprite, this.BoundsClipped.Y - yScreen + ySprite, this.BoundsClipped.Width, this.BoundsClipped.Height);
                var rectSprite    = surface.GetVisibleRectangle(xSprite, ySprite, widthSprite, heightSprite, false, false, sourceClipped);

                if (rectSprite.isVisible == false)
                {
                    return;
                }

                // on genere le rectangle affichable de l'ecran en prenant la taille de celui du rectangle de la source
                rectScreen = this.GetVisibleRectangle(this.BoundsClipped.X, this.BoundsClipped.Y, rectSprite.width, rectSprite.height, isHorizontalFlipped, isVerticalFlipped);

                if (rectScreen.isVisible == false)
                {
                    return;
                }

                sourceAddress      = rectSprite.address;
                destinationAddress = rectScreen.address;

                // compensation sur la destinationAddress
                if (isHorizontalFlipped == false)
                {
                    //if (rectSprite.x == 0)
                    //{
                    if (xScreen + widthSprite > BoundsClipped.Right)
                    {
                        destinationAddress += (this.BoundsClipped.Width - rectSprite.width);
                    }
                    else if (xScreen > BoundsClipped.X)
                    {
                        destinationAddress += xScreen - BoundsClipped.X;
                    }
                    //}
                }
                else
                {
                    if (rectSprite.x == xSprite)
                    {
                        if (xScreen + widthSprite > BoundsClipped.Right)
                        {
                            sourceAddress      += ((xScreen + widthSprite) - this.BoundsClipped.Right);
                            destinationAddress += (this.BoundsClipped.Width - rectSprite.width);
                        }
                        else if (xScreen > BoundsClipped.X)
                        {
                            destinationAddress += xScreen - BoundsClipped.X;
                        }
                    }
                    else
                    {
                        if (xScreen < BoundsClipped.X)
                        {
                            if (xScreen + widthSprite > BoundsClipped.Right)
                            {
                                // fn de ligne - distance entre xScreen et le x de la zone de clipping
                                sourceAddress += ((xScreen + widthSprite) - this.BoundsClipped.Right) - (BoundsClipped.X - xScreen);
                            }
                            else
                            {
                                sourceAddress += -rectSprite.x + xSprite;
                            }
                        }
                    }
                }

                // Vertical

                if (isVerticalFlipped == false)
                {
                    //if (rectSprite.y == 0)
                    //{
                    if (yScreen + heightSprite > BoundsClipped.Bottom)
                    {
                        destinationAddress += (this.BoundsClipped.Height - rectSprite.height) * this.Width;
                    }
                    else if (yScreen > BoundsClipped.Y)
                    {
                        destinationAddress += (yScreen - BoundsClipped.Y) * this.Width;
                    }
                    //}
                }
                else
                {
                    if (rectSprite.y == ySprite)
                    {
                        if (yScreen + heightSprite > BoundsClipped.Bottom)
                        {
                            sourceAddress      += ((yScreen + heightSprite) - this.BoundsClipped.Bottom) * surface.Width;
                            destinationAddress += (this.BoundsClipped.Height - rectSprite.height) * this.Width;
                        }
                        else if (yScreen > BoundsClipped.Y)
                        {
                            destinationAddress += (yScreen - BoundsClipped.Y) * this.Width;
                        }
                    }
                    else
                    {
                        if (yScreen < BoundsClipped.Y)
                        {
                            // Peut-on virer ce if ? et laisser seulement le else
                            // s'il n'arrive jamais dans le point d'arret c'est le cas
                            if (yScreen + heightSprite > BoundsClipped.Bottom)
                            {
                                // fn de ligne - distance entre xScreen et le x de la zone de clipping
                                sourceAddress += (((yScreen + heightSprite) - this.BoundsClipped.Bottom) - (BoundsClipped.Y - yScreen)) * surface.Width;
                            }
                            else
                            {
                                sourceAddress += (-rectSprite.y + ySprite) * surface.Width;
                            }
                        }
                    }
                }
            }

            // Affichage

            var strideDestination = rectScreen.stride;
            var strideSource      = surface.Width - Math.Min(surface.Width, rectScreen.width);

            var heightScreen = rectScreen.height;
            var widthScreen  = rectScreen.width;

            var destinationPixels = this.Pixels;
            var sourcePixels      = surface.Pixels;

            int destinationDirection = rectScreen.direction;

            //try
            //{
            for (int iy = 0; iy < heightScreen; iy++)
            {
                for (int ix = 0; ix < widthScreen; ix++)
                {
                    destinationPixels[destinationAddress].AlphaBlend(sourcePixels[sourceAddress], this.Opacity);

                    // sinon c'est invisible

                    sourceAddress++;
                    destinationAddress += destinationDirection;
                }

                destinationAddress += strideDestination;
                sourceAddress      += strideSource;
            }
            //}
            //catch (Exception ex)
            //{

            //}

            //if (HaveClip)
            //{
            //    // test : En Green affiche la source qui sera envoyé à destination
            //    DrawRectangle(rectScreen.x, rectScreen.y, rectScreen.width, rectScreen.height, Argb32.Green, false);
            //}
        }
Exemple #2
0
        /// <summary>
        /// Obtenir un rectangle à l'interieur de l'ecran (prend en compte le clipping de la surface + un clipping externe eventuellement)
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>

        private SurfaceRectangle GetVisibleRectangle(int x, int y, int width, int height, bool isFlipHorizontal, bool isFlipVertical, Rectangle?externalBoundsClipped = null)
        {
            SurfaceRectangle rectVisibility = new SurfaceRectangle();

            int direction;
            int stride;

            var rectRequested = new Rectangle(x, y, width, height); // taille demandé par le client

            rectRequested.Intersect(this.BoundsClipped);            // BoundsClipped est deja l'intersection entre clip et l'ecran

            // Rajoute la possibilité d'ajouté un clip externe (par exemple celui d'une destination sur une source)
            if (externalBoundsClipped != null)
            {
                rectRequested.Intersect(externalBoundsClipped.Value);
            }

            // L'interscetion entre la taille demandée et le clipping n'existe pas
            if (rectRequested.Width == 0 || rectRequested.Height == 0)
            {
                return(rectVisibility);
            }

            int position = this.GetPosition(rectRequested.X, rectRequested.Y);

            if (isFlipHorizontal == false)
            {
                stride    = this.Width - rectRequested.Width;
                direction = 1;
            }
            else
            {
                position += (rectRequested.Width - 1);
                direction = -1;
                stride    = this.Width + rectRequested.Width;
            }

            if (isFlipVertical == true)
            {
                position += (this.Width * (rectRequested.Height - 1));

                if (isFlipHorizontal == false)
                {
                    stride = -this.Width - rectRequested.Width;
                }
                else
                {
                    stride = -this.Width + rectRequested.Width;
                }
            }

            if (position == -1)
            {
                return(rectVisibility);
            }

            rectVisibility.direction = direction;
            rectVisibility.position  = position;
            rectVisibility.address   = this.Address + position;
            rectVisibility.stride    = stride;
            rectVisibility.width     = rectRequested.Width;
            rectVisibility.height    = rectRequested.Height;
            rectVisibility.isVisible = true;
            rectVisibility.x         = rectRequested.X;
            rectVisibility.y         = rectRequested.Y;

            return(rectVisibility);
        }