protected override void OnDisposing(bool manually) { base.OnDisposing(manually); // Dispose unmanaged Resources if (this.nativeTex != null) { this.nativeTex.Dispose(); this.nativeTex = null; } // Get rid of big data references, so the GC can collect them. this.basePixmap.Detach(); }
/// <summary> /// Retrieves the textures pixel data from video memory in the Rgba8 format. /// As a storage array type, either byte or <see cref="ColorRgba"/> is recommended. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="texture"></param> /// <param name="target">The buffer to store pixel values into.</param> /// <param name="dataLayout">The desired color layout of the specified buffer.</param> /// <param name="dataElementType">The desired color element type of the specified buffer.</param> public static void GetData <T>( this INativeTexture texture, T[] target, ColorDataLayout dataLayout, ColorDataElementType dataElementType) { using (PinnedArrayHandle pinned = new PinnedArrayHandle(target)) { texture.GetData( pinned.Address, dataLayout, dataElementType); } }
/// <summary> /// Sets up the Textures OpenGL resources, clearing previously uploaded pixel data. /// </summary> protected void SetupNativeRes() { if (this.nativeTex == null) { this.nativeTex = DualityApp.GraphicsBackend.CreateTexture(); } this.nativeTex.SetupEmpty( this.pixelformat, this.texWidth, this.texHeight, this.filterMin, this.filterMag, this.wrapX, this.wrapY, this.anisoFilter ? 4 : 0, this.HasMipmaps); }
/// <summary> /// Uploads the specified pixel data in RGBA format to video memory. A call to <see cref="INativeTexture.SetupEmpty"/> /// is to be considered required for this. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="texture"></param> /// <param name="format">The textures internal format.</param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="data">The block of pixel data to transfer.</param> /// <param name="dataLayout">The color layout of the specified data block.</param> /// <param name="dataElementType">The color element type of the specified data block.</param> public static void LoadData <T>( this INativeTexture texture, TexturePixelFormat format, int width, int height, T[] data, ColorDataLayout dataLayout, ColorDataElementType dataElementType) where T : struct { using (PinnedArrayHandle pinned = new PinnedArrayHandle(data)) { texture.LoadData( format, width, height, pinned.Address, dataLayout, dataElementType); } }
/// <summary> /// Loads the specified <see cref="Duality.Resources.Pixmap">Pixmaps</see> pixel data. /// </summary> /// <param name="basePixmap">The <see cref="Duality.Resources.Pixmap"/> that is used as pixel data source.</param> /// <param name="sizeMode">Specifies behaviour in case the source data has non-power-of-two dimensions.</param> public void LoadData(ContentRef <Pixmap> basePixmap, TextureSizeMode sizeMode) { if (this.nativeTex == null) { this.nativeTex = DualityApp.GraphicsBackend.CreateTexture(); } this.needsReload = false; this.basePixmap = basePixmap; this.texSizeMode = sizeMode; if (!this.basePixmap.IsExplicitNull) { PixelData pixelData = null; Pixmap basePixmapRes = this.basePixmap.IsAvailable ? this.basePixmap.Res : null; if (basePixmapRes != null) { pixelData = basePixmapRes.MainLayer; bool hasAtlas = (basePixmapRes.Atlas != null && basePixmapRes.Atlas.Count > 0); this.atlas = hasAtlas ? basePixmapRes.Atlas.ToArray() : null; } if (pixelData == null) { pixelData = Pixmap.Checkerboard.Res.MainLayer; } this.AdjustSize(pixelData.Width, pixelData.Height); this.SetupNativeRes(); if (this.texSizeMode != TextureSizeMode.NonPowerOfTwo && (this.pxWidth != this.texWidth || this.pxHeight != this.texHeight)) { if (this.texSizeMode == TextureSizeMode.Enlarge) { PixelData oldData = pixelData; pixelData = oldData.CloneResize(this.texWidth, this.texHeight); // Fill border pixels manually - that's cheaper than ColorTransparentPixels here. oldData.DrawOnto(pixelData, BlendMode.Solid, this.pxWidth, 0, 1, this.pxHeight, this.pxWidth - 1, 0); oldData.DrawOnto(pixelData, BlendMode.Solid, 0, this.pxHeight, this.pxWidth, 1, 0, this.pxHeight - 1); } else { pixelData = pixelData.CloneRescale(this.texWidth, this.texHeight, ImageScaleFilter.Linear); } } // Load pixel data to video memory this.nativeTex.LoadData( this.pixelformat, pixelData.Width, pixelData.Height, pixelData.Data, ColorDataLayout.Rgba, ColorDataElementType.Byte); // Adjust atlas to represent UV coordinates if (this.atlas != null) { Vector2 scale; scale.X = this.uvRatio.X / this.pxWidth; scale.Y = this.uvRatio.Y / this.pxHeight; for (int i = 0; i < this.atlas.Length; i++) { this.atlas[i].X *= scale.X; this.atlas[i].W *= scale.X; this.atlas[i].Y *= scale.Y; this.atlas[i].H *= scale.Y; } } } else { this.atlas = null; this.AdjustSize(this.size.X, this.size.Y); this.SetupNativeRes(); } }