예제 #1
0
        protected static Opacity ComputeOpacity(ITextureUpload upload)
        {
            // TODO: Investigate performance issues and revert functionality once we are sure there is no overhead.
            // see https://github.com/ppy/osu/issues/9307
            return(Opacity.Mixed);

            // ReadOnlySpan<Rgba32> data = upload.Data;
            //
            // if (data.Length == 0)
            //     return Opacity.Transparent;
            //
            // int firstPixelValue = data[0].A;
            //
            // // Check if the first pixel has partial transparency (neither fully-opaque nor fully-transparent).
            // if (firstPixelValue != 0 && firstPixelValue != 255)
            //     return Opacity.Mixed;
            //
            // // The first pixel is GUARANTEED to be either fully-opaque or fully-transparent.
            // // Now we need to go through the rest of the image and check that every other pixel matches this value.
            // for (int i = 1; i < data.Length; i++)
            // {
            //     if (data[i].A != firstPixelValue)
            //         return Opacity.Mixed;
            // }
            //
            // return firstPixelValue == 0 ? Opacity.Transparent : Opacity.Opaque;
        }
        internal override void SetData(ITextureUpload upload, WrapMode wrapModeS, WrapMode wrapModeT, Opacity?uploadOpacity)
        {
            // Can only perform padding when the bounds are a sub-part of the texture
            RectangleI middleBounds = upload.Bounds;

            if (middleBounds.IsEmpty || middleBounds.Width * middleBounds.Height > upload.Data.Length)
            {
                // For a texture atlas, we don't care about opacity, so we avoid
                // any computations related to it by assuming it to be mixed.
                base.SetData(upload, wrapModeS, wrapModeT, Opacity.Mixed);
                return;
            }

            int actualPadding = padding / (1 << upload.Level);

            if (wrapModeS != WrapMode.None && wrapModeT != WrapMode.None)
            {
                uploadCornerPadding(upload, middleBounds, actualPadding);
            }

            if (wrapModeS != WrapMode.None)
            {
                uploadHorizontalPadding(upload, middleBounds, actualPadding);
            }

            if (wrapModeT != WrapMode.None)
            {
                uploadVerticalPadding(upload, middleBounds, actualPadding);
            }

            // Upload the middle part of the texture
            // For a texture atlas, we don't care about opacity, so we avoid
            // any computations related to it by assuming it to be mixed.
            base.SetData(upload, wrapModeS, wrapModeT, Opacity.Mixed);
        }
예제 #3
0
        protected static Opacity ComputeOpacity(ITextureUpload upload)
        {
            // TODO: Investigate performance issues and revert functionality once we are sure there is no overhead.
            // see https://github.com/ppy/osu/issues/9307
            return(Opacity.Mixed);

            // if (upload.Data.Length == 0)
            //     return Opacity.Transparent;
            //
            // bool isTransparent = true;
            // bool isOpaque = true;
            //
            // for (int i = 0; i < upload.Data.Length; ++i)
            // {
            //     isTransparent &= upload.Data[i].A == 0;
            //     isOpaque &= upload.Data[i].A == 255;
            //
            //     if (!isTransparent && !isOpaque)
            //         return Opacity.Mixed;
            // }
            //
            // if (isTransparent)
            //     return Opacity.Transparent;
            //
            // return Opacity.Opaque;
        }
예제 #4
0
        protected override void DoUpload(ITextureUpload upload, IntPtr dataPointer)
        {
            if (!(upload is VideoTextureUpload videoUpload))
            {
                return;
            }

            // Do we need to generate a new texture?
            if (textureIds == null)
            {
                Debug.Assert(memoryLease == null);
                memoryLease = NativeMemoryTracker.AddMemory(this, Width * Height * 3 / 2);

                textureIds = new int[3];
                GL.GenTextures(textureIds.Length, textureIds);

                for (int i = 0; i < textureIds.Length; i++)
                {
                    GLWrapper.BindTexture(textureIds[i]);

                    if (i == 0)
                    {
                        int width  = videoUpload.Frame->width;
                        int height = videoUpload.Frame->height;

                        GL.TexImage2D(TextureTarget2d.Texture2D, 0, TextureComponentCount.R8, width, height, 0, PixelFormat.Red, PixelType.UnsignedByte, IntPtr.Zero);

                        textureSize += width * height;
                    }
                    else
                    {
                        int width  = (videoUpload.Frame->width + 1) / 2;
                        int height = (videoUpload.Frame->height + 1) / 2;

                        GL.TexImage2D(TextureTarget2d.Texture2D, 0, TextureComponentCount.R8, width, height, 0, PixelFormat.Red, PixelType.UnsignedByte, IntPtr.Zero);

                        textureSize += width * height;
                    }

                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);

                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
                }
            }

            for (int i = 0; i < textureIds.Length; i++)
            {
                GLWrapper.BindTexture(textureIds[i]);

                GL.PixelStore(PixelStoreParameter.UnpackRowLength, videoUpload.Frame->linesize[(uint)i]);
                GL.TexSubImage2D(TextureTarget2d.Texture2D, 0, 0, 0, videoUpload.Frame->width / (i > 0 ? 2 : 1), videoUpload.Frame->height / (i > 0 ? 2 : 1),
                                 PixelFormat.Red, PixelType.UnsignedByte, (IntPtr)videoUpload.Frame->data[(uint)i]);
            }

            GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);

            UploadComplete = true;
        }
예제 #5
0
        public Layer(SKBitmap image)
        {
            RelativeSizeAxes = Axes.Both;
            InternalChild    = Sprite = new Sprite()
            {
                RelativeSizeAxes = Axes.Both
            };

            IsVisible.ValueChanged += e => Alpha = e.NewValue ? 1 : 0;

            Image = null !; Canvas = null !; Upload = null !;
            SetImage(image);
        }
        private void uploadHorizontalPadding(ITextureUpload upload, RectangleI middleBounds, int actualPadding)
        {
            RectangleI[] sideBoundsArray =
            {
                new RectangleI(middleBounds.X - actualPadding,      middleBounds.Y, actualPadding, middleBounds.Height).Intersect(atlasBounds), // Left
                new RectangleI(middleBounds.X + middleBounds.Width, middleBounds.Y, actualPadding, middleBounds.Height).Intersect(atlasBounds), // Right
            };

            int[] sideIndices =
            {
                0,                      // Left
                middleBounds.Width - 1, // Right
            };

            for (int i = 0; i < 2; ++i)
            {
                RectangleI sideBounds = sideBoundsArray[i];

                if (!sideBounds.IsEmpty)
                {
                    bool allTransparentBlack = true;
                    int  index = sideIndices[i];

                    var sideUpload = new MemoryAllocatorTextureUpload(sideBounds.Width, sideBounds.Height)
                    {
                        Bounds = sideBounds
                    };

                    int stride = middleBounds.Width;

                    for (int y = 0; y < sideBounds.Height; ++y)
                    {
                        for (int x = 0; x < sideBounds.Width; ++x)
                        {
                            Rgba32 pixel = upload.Data[index + y * stride];
                            allTransparentBlack &= pixel == transparent_black;
                            sideUpload.RawData[y * sideBounds.Width + x] = pixel;
                        }
                    }

                    // Only upload padding if the border isn't completely transparent.
                    if (!allTransparentBlack)
                    {
                        // For a texture atlas, we don't care about opacity, so we avoid
                        // any computations related to it by assuming it to be mixed.
                        base.SetData(sideUpload, WrapMode.None, WrapMode.None, Opacity.Mixed);
                    }
                }
            }
        }
예제 #7
0
        internal override void SetData(ITextureUpload upload, WrapMode wrapModeS, WrapMode wrapModeT, Opacity?uploadOpacity)
        {
            if (uploadOpacity != null && uploadOpacity != Opacity.Opaque)
            {
                throw new InvalidOperationException("Video texture uploads must always be opaque");
            }

            UploadComplete = false;

            // We do not support videos with transparency at this point,
            // so the upload's opacity as well as the texture's opacity
            // is always opaque.
            base.SetData(upload, wrapModeS, wrapModeT, Opacity = Opacity.Opaque);
        }
예제 #8
0
        protected void UpdateOpacity(ITextureUpload upload, ref Opacity?uploadOpacity)
        {
            // Compute opacity if it doesn't have a value yet
            uploadOpacity ??= ComputeOpacity(upload);

            // Update the texture's opacity depending on the upload's opacity.
            // If the upload covers the entire bounds of the texture, it fully
            // determines the texture's opacity. Otherwise, it can only turn
            // the texture's opacity into a mixed state (if it disagrees with
            // the texture's existing opacity).
            if (upload.Bounds == Bounds && upload.Level == 0)
            {
                Opacity = uploadOpacity.Value;
            }
            else if (uploadOpacity.Value != Opacity)
            {
                Opacity = Opacity.Mixed;
            }
        }
        private void uploadCornerPadding(ITextureUpload upload, RectangleI middleBounds, int actualPadding)
        {
            RectangleI[] cornerBoundsArray =
            {
                new RectangleI(middleBounds.X - actualPadding,      middleBounds.Y - actualPadding,       actualPadding, actualPadding).Intersect(atlasBounds), // TopLeft
                new RectangleI(middleBounds.X + middleBounds.Width, middleBounds.Y - actualPadding,       actualPadding, actualPadding).Intersect(atlasBounds), // TopRight
                new RectangleI(middleBounds.X - actualPadding,      middleBounds.Y + middleBounds.Height, actualPadding, actualPadding).Intersect(atlasBounds), // BottomLeft
                new RectangleI(middleBounds.X + middleBounds.Width, middleBounds.Y + middleBounds.Height, actualPadding, actualPadding).Intersect(atlasBounds), // BottomRight
            };

            int[] cornerIndices =
            {
                0,                                                                       // TopLeft
                middleBounds.Width - 1,                                                  // TopRight
                (middleBounds.Height - 1) * middleBounds.Width,                          // BottomLeft
                (middleBounds.Height - 1) * middleBounds.Width + middleBounds.Width - 1, // BottomRight
            };

            for (int i = 0; i < 4; ++i)
            {
                RectangleI cornerBounds  = cornerBoundsArray[i];
                int        nCornerPixels = cornerBounds.Width * cornerBounds.Height;
                Rgba32     cornerPixel   = upload.Data[cornerIndices[i]];

                // Only upload if we have a non-zero size and if the colour isn't already transparent black
                if (nCornerPixels > 0 && cornerPixel != transparent_black)
                {
                    var cornerUpload = new MemoryAllocatorTextureUpload(cornerBounds.Width, cornerBounds.Height)
                    {
                        Bounds = cornerBounds
                    };
                    for (int j = 0; j < nCornerPixels; ++j)
                    {
                        cornerUpload.RawData[j] = cornerPixel;
                    }

                    // For a texture atlas, we don't care about opacity, so we avoid
                    // any computations related to it by assuming it to be mixed.
                    base.SetData(cornerUpload, WrapMode.None, WrapMode.None, Opacity.Mixed);
                }
            }
        }
예제 #10
0
 /// <summary>
 /// Sets the pixel data of this <see cref="TextureGLAtlas"/>.
 /// </summary>
 /// <param name="upload">The <see cref="ITextureUpload"/> containing the data.</param>
 /// <param name="wrapModeS">The texture wrap mode in horizontal direction.</param>
 /// <param name="wrapModeT">The texture wrap mode in vertical direction.</param>
 /// <param name="uploadOpacity">Whether the upload is opaque, transparent, or a mix of both..</param>
 internal abstract void SetData(ITextureUpload upload, WrapMode wrapModeS, WrapMode wrapModeT, Opacity?uploadOpacity);
예제 #11
0
 /// <summary>
 /// Sets the pixel data of this <see cref="TextureGL"/>.
 /// </summary>
 /// <param name="upload">The <see cref="ITextureUpload"/> containing the data.</param>
 public void SetData(ITextureUpload upload) => SetData(upload, WrapModeS, WrapModeT, null);
예제 #12
0
 public abstract void SetData(ITextureUpload upload);
예제 #13
0
        public override void SetData(ITextureUpload upload)
        {
            UploadComplete = false;

            base.SetData(upload);
        }