/// <summary> /// Create texture from pixel array /// </summary> public void LoadImage(Color4[] pixels, int width, int height) { IsStubTexture = false; reloader = new TexturePixelArrayReloader(pixels, width, height); MemoryUsed = 4 * width * height; ImageSize = new Size(width, height); SurfaceSize = ImageSize; uvRect = new Rectangle(0, 0, 1, 1); Window.Current.InvokeOnRendering(() => { var pinnedArray = GCHandle.Alloc(pixels, GCHandleType.Pinned); var pointer = pinnedArray.AddrOfPinnedObject(); PrepareOpenGLTexture(); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pointer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); pinnedArray.Free(); }); }
private void ReadCompressedImage(ref Action glCommands, BinaryReader reader, int level, int width, int height, int linearSize, UInt32 pfFourCC) { var pif = (PixelInternalFormat)All.CompressedRgbS3tcDxt1Ext; switch ((DDSFourCC)pfFourCC) { case DDSFourCC.DXT1: pif = (PixelInternalFormat)All.CompressedRgbS3tcDxt1Ext; break; case DDSFourCC.DXT3: pif = (PixelInternalFormat)All.CompressedRgbaS3tcDxt3Ext; break; case DDSFourCC.DXT5: pif = (PixelInternalFormat)All.CompressedRgbaS3tcDxt5Ext; break; default: throw new InvalidDataException("Unsupported texture format"); } var buffer = ReadTextureData(reader, linearSize); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.CompressedTexImage2D(TextureTarget.Texture2D, level, pif, width, height, 0, buffer.Length, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; }
private void SetTextureParameter(TextureParameterName name, int value) { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexParameter(TextureTarget.Texture2D, name, value); PlatformRenderer.MarkTextureSlotAsDirty(0); }
private void CreateTexture() { if (IsDisposed) { throw new ObjectDisposedException(GetType().Name); } var t = new uint[1]; GL.GenFramebuffers(1, t); framebuffer = t[0]; GL.GenTextures(1, t); handle = t[0]; GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, textureParams.MinFilter.ToInt()); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, textureParams.MagFilter.ToInt()); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, textureParams.WrapModeU.ToInt()); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, textureParams.WrapModeV.ToInt()); int bpp; if (Format == RenderTextureFormat.RGBA8) { GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, size.Width, size.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, (IntPtr)null); bpp = 4; } else { GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, size.Width, size.Height, 0, PixelFormat.Rgb, PixelType.UnsignedShort565, (IntPtr)null); bpp = 2; } MemoryUsed = SurfaceSize.Width * SurfaceSize.Height * bpp; uint oldFramebuffer = PlatformRenderer.CurrentFramebuffer; PlatformRenderer.BindFramebuffer(framebuffer); PlatformRenderer.CheckErrors(); GL.FramebufferTexture2D( FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, TextureTarget.Texture2D, handle, level: 0); if ((int)GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != (int)FramebufferErrorCode.FramebufferComplete) { throw new Exception("Failed to create render texture. Framebuffer is incomplete."); } AttachRenderBuffer(FramebufferSlot.DepthAttachment, RenderbufferInternalFormat.DepthComponent16, out depthBuffer); Renderer.Clear(Color4.Black); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.BindFramebuffer(oldFramebuffer); PlatformRenderer.CheckErrors(); }
/// <summary> /// Load subtexture from pixel array /// Warning: this method doesn't support automatic texture reload after restoring graphics context /// </summary> public void LoadSubImage(Color4[] pixels, int x, int y, int width, int height) { IsStubTexture = false; Window.Current.InvokeOnRendering(() => { PrepareOpenGLTexture(); GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexSubImage2D(TextureTarget.Texture2D, 0, x, y, width, height, PixelFormat.Rgba, PixelType.UnsignedByte, pixels); PlatformRenderer.CheckErrors(); PlatformRenderer.MarkTextureSlotAsDirty(0); }); }
private void ReadRGBAImage(ref Action glCommands, BinaryReader reader, int level, int width, int height, int pitch) { if (pitch != width * 4) { throw new InvalidDataException("Error reading RGBA texture. Must be 32 bit rgba"); } var buffer = ReadTextureData(reader, pitch * height); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexImage2D(TextureTarget.Texture2D, level, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; }
private void PrepareOpenGLTexture() { // Generate a new texture. if (handle == 0) { var t = new int[1]; GL.GenTextures(1, t); handle = (uint)t[0]; } GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, textureParams.MinFilter.ToInt()); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, textureParams.MagFilter.ToInt()); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, textureParams.WrapModeU.ToInt()); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, textureParams.WrapModeV.ToInt()); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }
private void InitWithPVRTexture(BinaryReader reader) { var version = reader.ReadUInt32(); if (version != PVRMagic) { throw new Exception("Invalid PVR header"); } reader.ReadUInt32(); // flags var pixelFormat = (PVRFormat)reader.ReadUInt64(); reader.ReadUInt32(); // color space reader.ReadUInt32(); // channel type var height = reader.ReadInt32(); var width = reader.ReadInt32(); reader.ReadUInt32(); // depth reader.ReadUInt32(); // num surfaces reader.ReadUInt32(); // num faces var numMipmaps = reader.ReadInt32(); var metaDataSize = reader.ReadInt32(); if (metaDataSize > 0) { reader.ReadChars(metaDataSize); } SurfaceSize = ImageSize = new Size(width, height); Action glCommands = PrepareOpenGLTexture; MemoryUsed = 0; for (int i = 0; i < numMipmaps; i++) { if (i > 0 && (width < 8 || height < 8)) { continue; } // Cloning variables to prevent wrong capturing int mipLevel = i; int width2 = width; int height2 = height; switch (pixelFormat) { #if iOS case PVRFormat.PVRTC_4_RGBA: { var buffer = ReadTextureData(reader, width * height * 4 / 8); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.CompressedTexImage2D(All.Texture2D, mipLevel, All.CompressedRgbaPvrtc4Bppv1Img, width2, height2, 0, buffer.Length, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; break; } case PVRFormat.PVRTC_2_RGBA: { if (i > 0 && height < 16) { continue; } var buffer = ReadTextureData(reader, width * height * 2 / 8); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.CompressedTexImage2D(All.Texture2D, mipLevel, All.CompressedRgbaPvrtc2Bppv1Img, width2, height2, 0, buffer.Length, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; break; } #elif ANDROID case PVRFormat.ETC1: { var buffer = ReadTextureData(reader, width * height * 4 / 8); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.CompressedTexImage2D(All.Texture2D, mipLevel, All.Etc1Rgb8Oes, width2, height2, 0, buffer.Length, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; break; } #endif case PVRFormat.RGBA4444: { var buffer = ReadTextureData(reader, width * height * 2); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexImage2D(TextureTarget.Texture2D, mipLevel, PixelInternalFormat.Rgba, width2, height2, 0, PixelFormat.Rgba, PixelType.UnsignedShort4444, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; break; } case PVRFormat.RGB565: { var buffer = ReadTextureData(reader, width * height * 2); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexImage2D(TextureTarget.Texture2D, mipLevel, PixelInternalFormat.Rgb, width2, height2, 0, PixelFormat.Rgb, PixelType.UnsignedShort565, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; break; } case PVRFormat.RGBA8888: { var buffer = ReadTextureData(reader, width * height * 4); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexImage2D(TextureTarget.Texture2D, mipLevel, PixelInternalFormat.Rgba, width2, height2, 0, PixelFormat.Rgba, PixelType.UnsignedByte, buffer); PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; break; } default: throw new NotImplementedException(); } width /= 2; height /= 2; } Window.Current.InvokeOnRendering(glCommands); }
private void InitWithKTXTexture(BinaryReader reader) { var identifier = reader.ReadBytes(12); if (identifier[1] != 'K' || identifier[2] != 'T' || identifier[3] != 'X') { throw new InvalidDataException("Invalid KTX header"); } var endiannes = reader.ReadUInt32(); if (endiannes != 0x04030201) { throw new InvalidDataException("Unsupported endiannes"); } var glType = reader.ReadInt32(); var glTypeSize = reader.ReadInt32(); var glFormat = reader.ReadInt32(); var glInternalFormat = reader.ReadInt32(); var glBaseInternalFormat = reader.ReadInt32(); var pixelWidth = reader.ReadInt32(); var pixelHeight = reader.ReadInt32(); var pixelDepth = reader.ReadInt32(); var numberOfArrayElements = reader.ReadInt32(); var numberOfFaces = reader.ReadInt32(); var numberOfMipmapLevels = reader.ReadInt32(); var bytesOfKeyValueData = reader.ReadInt32(); reader.ReadBytes(bytesOfKeyValueData); if (numberOfArrayElements != 0) { throw new InvalidDataException("Array textures are not supported"); } if (numberOfFaces != 1) { throw new InvalidDataException("Cubemap textures are not supported"); } if (pixelDepth != 0) { throw new InvalidDataException("3D Textures are not supported"); } if ((pixelWidth & 3) != 0 || (pixelHeight & 3) != 0) { throw new InvalidDataException("Texture dimensions should multiple of 4"); } SurfaceSize = ImageSize = new Size(pixelWidth, pixelHeight); Action glCommands = PrepareOpenGLTexture; PrepareOpenGLTexture(); for (int i = 0; i < Math.Max(1, numberOfMipmapLevels); i++) { var dataLength = reader.ReadInt32(); MemoryUsed = 0; if (i > 0 && (pixelWidth < 8 || pixelHeight < 8)) { continue; } // Copy variables because they will be captured. int mipLevel = i; int width = pixelWidth; int height = pixelHeight; if (glFormat == 0) { var data = ReadTextureData(reader, dataLength); glCommands += () => { if (!etc2Checked) { etc2Checked = true; if (PlatformRenderer.GetGLESMajorVersion() >= 3) { etc2Supported = true; } else { var ext = GL.GetString(StringName.Extensions); etc2Supported = ext?.Contains("ETC2_RGBA8") ?? false; } Debug.Write(etc2Supported ? "ETC2 textures supported." : "ETC2 textures not supported."); } GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); const int etc1Rgb8Oes = 36196; if (etc2Supported || (Application.Platform == PlatformId.Android && glInternalFormat == etc1Rgb8Oes)) { #pragma warning disable CS0618 GL.CompressedTexImage2D( TextureTarget.Texture2D, mipLevel, (PixelInternalFormat)glInternalFormat, width, height, 0, dataLength, data); } else { var rgba8Data = Marshal.AllocHGlobal(width * height * 4); Etc2Decoder.Decode(data, rgba8Data, width, height, glInternalFormat); GL.TexImage2D(TextureTarget.Texture2D, mipLevel, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, rgba8Data); Marshal.FreeHGlobal(rgba8Data); } PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; } else { var data = ReadTextureData(reader, dataLength); glCommands += () => { GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, handle); GL.TexImage2D( TextureTarget.Texture2D, mipLevel, (PixelInternalFormat)glInternalFormat, width, height, 0, (PixelFormat)glFormat, (PixelType)glType, data); #pragma warning restore CS0618 PlatformRenderer.MarkTextureSlotAsDirty(0); PlatformRenderer.CheckErrors(); }; } pixelWidth /= 2; pixelHeight /= 2; } Window.Current.InvokeOnRendering(glCommands); }