/// <summary> /// Gets the OpenGL texture format flag that corresponds to the specified texture data format. /// </summary> /// <param name="format">The texture data format to convert.</param> /// <returns>The converted texture data format.</returns> private static UInt32 GetOpenGLTextureFormat(TextureDataFormat format) { switch (format) { case TextureDataFormat.RGBA: return(gl.GL_RGBA); case TextureDataFormat.BGRA: return(gl.GL_BGRA); } throw new NotSupportedException("format"); }
public override void Serialize(SerializedAssets serializedAssets, object[] serializeOptions, NodeBase objNode, List <Action <NodeBase> > postSerializeActions) { #if UNITY_EDITOR //Make sure this is always 36 characters long. this.referenceID = this.rootNode.GenerateID(); ComponentNode componentNode = new ComponentNode(PCFResourceType.TEXTURE, referenceID, null); //Component nodes must always be parented to objNodes. objNode.AddChildNode(componentNode); if (this.texture != null) { TextureSerializeOpts serializeOption = null; for (int i = 0; i < serializeOptions.Length; i++) { object opt = serializeOptions[i]; if (opt is TextureSerializeOpts) { serializeOption = opt as TextureSerializeOpts; break; } } if (serializeOption == null) { return; } //Create serialized asset by converting data to a bytearray and give it to the constructor. AssetResource resource = new AssetResource(false); TextureDataFormat format = TextureDataFormat.Empty; byte[] textureData = serializeOption.PackageTexture(this.texture, serializedAssets, referenceID, ref format); JObject metaData = new JObject(); metaData["width"] = this.texture.width; metaData["height"] = this.texture.height; metaData["textureFormat"] = (int)format; byte[] metaDataBuffer = System.Text.Encoding.UTF8.GetBytes(metaData.ToString(Formatting.None)); resource.Serialize(referenceID, MetaDataType.JSON, metaDataBuffer, textureData); serializedAssets.AddResource(referenceID, PCFResourceType.TEXTURE, resource); //Nodes store their resource when serializing componentNode.SetSerializer(this); } #endif }
private static byte[] DecompressDxtBlock(EndianBinaryReader reader, TextureDataFormat format) { byte[] outputData = new byte[(4 * 4) * 4]; byte[] colorData = null, alphaData = null; if (format != TextureDataFormat.DXT1) { alphaData = DecompressDxtAlpha(reader, format); } colorData = DecompressDxtColor(reader, format); for (int i = 0; i < colorData.Length; i += 4) { outputData[i] = colorData[i]; outputData[i + 1] = colorData[i + 1]; outputData[i + 2] = colorData[i + 2]; outputData[i + 3] = (alphaData != null ? alphaData[i + 3] : colorData[i + 3]); } return(outputData); }
public virtual byte[] PackageTexture(Texture2D texture, SerializedAssets serializedAssets, UInt32 nodeID, ref TextureDataFormat format) { if (packageOption == TexturePackageOptions.ASTCPackage) { string cachedASTC = GetCachedASTC(texture); if (File.Exists(cachedASTC)) { TextureEncoderBase encoder = encoders["astc"]; byte[] astcData = encoder.GetData(cachedASTC, 1); format = TextureDataFormat.ASTC6X6; return(astcData); } } else if (packageOption == TexturePackageOptions.PVRTCPackage) { string cachedPVRTC = GetCachedPVRTC(texture); Debug.Log(cachedPVRTC); if (File.Exists(cachedPVRTC)) { TextureEncoderBase encoder = encoders["pvrtc"]; byte[] pvrtcData = encoder.GetData(cachedPVRTC, 1); format = TextureDataFormat.PVRTC4BPP; return(pvrtcData); } } else if (packageOption == TexturePackageOptions.IncompletePackage) { string cachedASTC = GetCachedASTC(texture); string cachedPVRTC = GetCachedPVRTC(texture); string outputDirectory = serializedAssets.GetDestinationDirectory(); bool hasCache = true; if (hasCache = File.Exists(cachedASTC)) { TextureEncoderBase encoder = encoders["astc"]; byte[] texData = encoder.GetData(cachedASTC, 1); format = TextureDataFormat.Empty; string pvrtcPath = outputDirectory + "/" + nodeID + ".astc"; TextureEncoderBase.SaveTextureToDisk(pvrtcPath, texData); } else if (hasCache = File.Exists(cachedPVRTC)) { TextureEncoderBase encoder = encoders["pvrtc"]; byte[] texData = encoder.GetData(cachedASTC, 1); format = TextureDataFormat.Empty; string pvrtcPath = outputDirectory + "/" + nodeID + ".pvrtc"; TextureEncoderBase.SaveTextureToDisk(pvrtcPath, texData); } //Incase a cached texture resource was used we dont serialize the texture into the node, its left empty. if (hasCache) { return(null); } } //Default is packaging textures are raw rgba. byte[] textureData = TextureEncoderBase.GetImageBytes(texture); format = TextureDataFormat.RGB32; return(textureData); }
/// <inheritdoc/> public override void SetData(Int32 level, Rectangle?rect, IntPtr data, Int32 offset, Int32 count, Int32 stride, TextureDataFormat format, SetDataOrigin origin = SetDataOrigin.TopLeft) { if (willNotBeSampled) { throw new NotSupportedException(OpenGLStrings.RenderBufferWillNotBeSampled); } texture.SetData(level, rect, data, offset, count, stride, format, origin); }
private static byte[] DecompressDxtColor(EndianBinaryReader reader, TextureDataFormat format) { byte[] colorOut = new byte[(4 * 4) * 4]; ushort color0 = reader.ReadUInt16(Endian.LittleEndian); ushort color1 = reader.ReadUInt16(Endian.LittleEndian); uint bits = reader.ReadUInt32(Endian.LittleEndian); byte c0r, c0g, c0b, c1r, c1g, c1b; UnpackRgb565(color0, out c0r, out c0g, out c0b); UnpackRgb565(color1, out c1r, out c1g, out c1b); byte[] bitsExt = new byte[16]; for (int i = 0; i < bitsExt.Length; i++) { bitsExt[i] = (byte)((bits >> (i * 2)) & 0x3); } for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { byte code = bitsExt[(y * 4) + x]; int destOffset = ((y * 4) + x) * 4; if (format == TextureDataFormat.DXT1) { colorOut[destOffset + 3] = (byte)((color0 <= color1 && code == 3) ? 0 : 0xFF); } if (format == TextureDataFormat.DXT1 && color0 <= color1) { switch (code) { case 0x00: colorOut[destOffset + 0] = c0b; colorOut[destOffset + 1] = c0g; colorOut[destOffset + 2] = c0r; break; case 0x01: colorOut[destOffset + 0] = c1b; colorOut[destOffset + 1] = c1g; colorOut[destOffset + 2] = c1r; break; case 0x02: colorOut[destOffset + 0] = (byte)((c0b + c1b) / 2); colorOut[destOffset + 1] = (byte)((c0g + c1g) / 2); colorOut[destOffset + 2] = (byte)((c0r + c1r) / 2); break; case 0x03: colorOut[destOffset + 0] = 0; colorOut[destOffset + 1] = 0; colorOut[destOffset + 2] = 0; break; } } else { switch (code) { case 0x00: colorOut[destOffset + 0] = c0b; colorOut[destOffset + 1] = c0g; colorOut[destOffset + 2] = c0r; break; case 0x01: colorOut[destOffset + 0] = c1b; colorOut[destOffset + 1] = c1g; colorOut[destOffset + 2] = c1r; break; case 0x02: colorOut[destOffset + 0] = (byte)((2 * c0b + c1b) / 3); colorOut[destOffset + 1] = (byte)((2 * c0g + c1g) / 3); colorOut[destOffset + 2] = (byte)((2 * c0r + c1r) / 3); break; case 0x03: colorOut[destOffset + 0] = (byte)((c0b + 2 * c1b) / 3); colorOut[destOffset + 1] = (byte)((c0g + 2 * c1g) / 3); colorOut[destOffset + 2] = (byte)((c0r + 2 * c1r) / 3); break; } } } } return(colorOut); }
private static byte[] DecompressDxtAlpha(EndianBinaryReader reader, TextureDataFormat format) { byte[] alphaOut = new byte[(4 * 4) * 4]; if (format == TextureDataFormat.DXT3) { ulong alpha = reader.ReadUInt64(); for (int i = 0; i < alphaOut.Length; i += 4) { alphaOut[i + 3] = (byte)(((alpha & 0xF) << 4) | (alpha & 0xF)); alpha >>= 4; } } else if (format == TextureDataFormat.DXT5) { byte alpha0 = reader.ReadByte(); byte alpha1 = reader.ReadByte(); byte bits_5 = reader.ReadByte(); byte bits_4 = reader.ReadByte(); byte bits_3 = reader.ReadByte(); byte bits_2 = reader.ReadByte(); byte bits_1 = reader.ReadByte(); byte bits_0 = reader.ReadByte(); ulong bits = (ulong)(((ulong)bits_0 << 40) | ((ulong)bits_1 << 32) | ((ulong)bits_2 << 24) | ((ulong)bits_3 << 16) | ((ulong)bits_4 << 8) | (ulong)bits_5); byte[] bitsExt = new byte[16]; for (int i = 0; i < bitsExt.Length; i++) { bitsExt[i] = (byte)((bits >> (i * 3)) & 0x7); } for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { byte code = bitsExt[(y * 4) + x]; int destOffset = (((y * 4) + x) * 4) + 3; if (alpha0 > alpha1) { switch (code) { case 0x00: alphaOut[destOffset] = alpha0; break; case 0x01: alphaOut[destOffset] = alpha1; break; case 0x02: alphaOut[destOffset] = (byte)((6 * alpha0 + 1 * alpha1) / 7); break; case 0x03: alphaOut[destOffset] = (byte)((5 * alpha0 + 2 * alpha1) / 7); break; case 0x04: alphaOut[destOffset] = (byte)((4 * alpha0 + 3 * alpha1) / 7); break; case 0x05: alphaOut[destOffset] = (byte)((3 * alpha0 + 4 * alpha1) / 7); break; case 0x06: alphaOut[destOffset] = (byte)((2 * alpha0 + 5 * alpha1) / 7); break; case 0x07: alphaOut[destOffset] = (byte)((1 * alpha0 + 6 * alpha1) / 7); break; } } else { switch (code) { case 0x00: alphaOut[destOffset] = alpha0; break; case 0x01: alphaOut[destOffset] = alpha1; break; case 0x02: alphaOut[destOffset] = (byte)((4 * alpha0 + 1 * alpha1) / 5); break; case 0x03: alphaOut[destOffset] = (byte)((3 * alpha0 + 2 * alpha1) / 5); break; case 0x04: alphaOut[destOffset] = (byte)((2 * alpha0 + 3 * alpha1) / 5); break; case 0x05: alphaOut[destOffset] = (byte)((1 * alpha0 + 4 * alpha1) / 5); break; case 0x06: alphaOut[destOffset] = 0x00; break; case 0x07: alphaOut[destOffset] = 0xFF; break; } } } } } return(alphaOut); }
/// <summary> /// Sets the texture's data. /// </summary> /// <param name="level">The mipmap level for which to set data.</param> /// <param name="rect">A rectangle describing the position and size of the data to set.</param> /// <param name="data">A pointer to the data to set.</param> /// <param name="offset">The index of the first element to set.</param> /// <param name="count">The number of elements to set.</param> /// <param name="stride">The number of elements in one row of data.</param> /// <param name="format">The format of the data being set.</param> /// <param name="origin">A <see cref="SetDataOrigin"/> value specifying the origin of the texture data in <paramref name="data"/>.</param> private unsafe void SetDataInternal(Int32 level, Rectangle?rect, IntPtr data, Int32 offset, Int32 count, Int32 stride, TextureDataFormat format, SetDataOrigin origin) { var region = rect ?? new Rectangle(0, 0, width, height); if (region.Width * region.Height != count) { throw new InvalidOperationException(UltravioletStrings.BufferIsWrongSize); } const Int32 SizeOfTextureElementInBytes = 4; var flipHorizontally = (origin == SetDataOrigin.TopRight || origin == SetDataOrigin.BottomRight); var flipVertically = (origin == SetDataOrigin.TopLeft || origin == SetDataOrigin.TopRight); TextureUtil.ReorientTextureData(data.ToPointer(), region.Width, region.Height, SizeOfTextureElementInBytes, flipHorizontally, flipVertically); if (flipHorizontally) { region = new Rectangle((width - region.Width) - region.X, region.Y, region.Width, region.Height); } if (flipVertically) { region = new Rectangle(region.X, (height - region.Height) - region.Y, region.Width, region.Height); } using (OpenGLState.ScopedBindTexture2D(texture)) { var rowLengthSupported = (!gl.IsGLES2 || gl.IsExtensionSupported("GL_EXT_unpack_subimage")); var rowLengthFallbackRequired = (stride != 0 && !rowLengthSupported); if (rowLengthFallbackRequired) { var ptr = (Byte *)data.ToPointer(); for (int i = 0; i < height; i++) { gl.TextureSubImage2D(texture, gl.GL_TEXTURE_2D, level, region.X, region.Y + i, region.Width, 1, GetOpenGLTextureFormat(format), gl.GL_UNSIGNED_BYTE, ptr); ptr += stride * 4; } } else { if (rowLengthSupported) { gl.PixelStorei(gl.GL_UNPACK_ROW_LENGTH, stride); gl.ThrowIfError(); } gl.PixelStorei(gl.GL_UNPACK_ALIGNMENT, 1); gl.ThrowIfError(); gl.TextureSubImage2D(texture, gl.GL_TEXTURE_2D, level, region.X, region.Y, region.Width, region.Height, GetOpenGLTextureFormat(format), gl.GL_UNSIGNED_BYTE, data.ToPointer()); gl.ThrowIfError(); if (rowLengthSupported) { gl.PixelStorei(gl.GL_UNPACK_ROW_LENGTH, 0); gl.ThrowIfError(); } } } }
/// <inheritdoc/> public override void SetData(Int32 level, Rectangle?rect, IntPtr data, Int32 offset, Int32 count, Int32 stride, TextureDataFormat format, SetDataOrigin origin = SetDataOrigin.TopLeft) { Contract.EnsureNotDisposed(this, Disposed); SetDataInternal(level, rect, data, offset, count, stride, format, origin); }
/// <summary> /// Sets the texture's data. /// </summary> /// <param name="level">The mipmap level for which to set data.</param> /// <param name="rect">A rectangle describing the position and size of the data to set.</param> /// <param name="data">A pointer to the data to set.</param> /// <param name="offset">The index of the first element to set.</param> /// <param name="count">The number of elements to set.</param> /// <param name="stride">The number of elements in one row of data.</param> /// <param name="format">The format of the data being set.</param> /// <param name="origin">A <see cref="SetDataOrigin"/> value specifying the origin of the texture data in <paramref name="data"/>.</param> private unsafe void SetDataInternal(Int32 level, Rectangle?rect, IntPtr data, Int32 offset, Int32 count, Int32 stride, TextureDataFormat format, SetDataOrigin origin) { var region = rect ?? new Rectangle(0, 0, width, height); if (region.Width * region.Height != count) { throw new InvalidOperationException(UltravioletStrings.BufferIsWrongSize); } const Int32 SizeOfTextureElementInBytes = 4; var flipHorizontally = (origin == SetDataOrigin.TopRight || origin == SetDataOrigin.BottomRight); var flipVertically = (origin == SetDataOrigin.TopLeft || origin == SetDataOrigin.TopRight); TextureUtil.ReorientTextureData(data.ToPointer(), region.Width, region.Height, SizeOfTextureElementInBytes, flipHorizontally, flipVertically); if (flipHorizontally) { region = new Rectangle((width - region.Width) - region.X, region.Y, region.Width, region.Height); } if (flipVertically) { region = new Rectangle(region.X, (height - region.Height) - region.Y, region.Width, region.Height); } using (OpenGLState.ScopedBindTexture2D(texture)) { gl.PixelStorei(gl.GL_UNPACK_ROW_LENGTH, stride); gl.ThrowIfError(); gl.PixelStorei(gl.GL_UNPACK_ALIGNMENT, 1); gl.ThrowIfError(); gl.TextureSubImage2D(texture, gl.GL_TEXTURE_2D, level, region.X, region.Y, region.Width, region.Height, GetOpenGLTextureFormat(format), gl.GL_UNSIGNED_BYTE, data.ToPointer()); gl.ThrowIfError(); gl.PixelStorei(gl.GL_UNPACK_ROW_LENGTH, 0); gl.ThrowIfError(); } }
public override void Deserialize(Dictionary <PCFResourceType, DataBlockBase> dataBlocks, UnityNodeBase parentNode, ResourceResponse resourceResponse, List <Action <UnityNodeBase> > postInstallActions, bool optimizedLoad) { if (!this.isDeserialized) { ResourceBlock dataBlock = dataBlocks[this.resourceType] as ResourceBlock; AssetResource resource = dataBlock.GetResource(this.referenceID); if (resource == null) { ResourceResponse textureLookUp = resourceResponse.CanHandle(GetReferenceID()); if (textureLookUp != null) { textureLookUp.HandleTextureResponse(null); } return; } byte[] textureBytes = resource.GetResourceData(); byte[] metaDataBuffer = resource.GetMetaData(); JObject metaData = JObject.Parse(System.Text.Encoding.UTF8.GetString(metaDataBuffer)); int width = metaData.Value <int>("width"); int height = metaData.Value <int>("height"); TextureDataFormat textureFormat = (TextureDataFormat)metaData.Value <int>("textureFormat"); string fieldName = metaData.Value <string>("fieldName"); if (textureFormat == TextureDataFormat.PVRTC4BPP) { #if MEASURE_PERFORMANCE System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); #endif #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_EDITOR int dataSize = 0; IntPtr dataPointer = PVRTCEncoderWrapper.DecompressData(textureBytes, width, height, false, ref dataSize); if (dataPointer != IntPtr.Zero) { this.texture = new Texture2D(width, height, TextureFormat.RGBA32, false); this.texture.LoadRawTextureData(dataPointer, dataSize); this.texture.Apply(false, true); //TODO: Probably better to use IDisposable here.... PVRTCEncoderWrapper.FreeCompressedDataPointer(dataPointer); } #else this.texture = new Texture2D(width, height, TextureFormat.PVRTC_RGBA4, false); this.texture.LoadRawTextureData(textureBytes); this.texture.Apply(false, true); #endif #if MEASURE_PERFORMANCE watch.Stop(); Debug.Log("Time to deserialize texture: " + watch.ElapsedMilliseconds); #endif } else if (textureFormat == TextureDataFormat.ASTC6X6) { #if MEASURE_PERFORMANCE System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); #endif this.texture = new Texture2D(width, height, TextureFormat.ASTC_RGBA_6x6, false); this.texture.LoadRawTextureData(textureBytes); this.texture.Apply(false, true); #if MEASURE_PERFORMANCE watch.Stop(); Debug.Log("Time to deserialize texture: " + watch.ElapsedMilliseconds); #endif } else if (textureFormat == TextureDataFormat.RGB32) { this.texture = new Texture2D(width, height, TextureFormat.RGBA32, false); this.texture.LoadRawTextureData(textureBytes); if (optimizedLoad) { this.texture.Apply(false, true); } else { this.texture.Apply(false); } } if (fieldName == null) { ResourceResponse request = resourceResponse.CanHandle(GetReferenceID()); if (request != null) { request.HandleTextureResponse(texture); } } else { if (resourceResponse != null) { resourceResponse.GetFieldDeserializer.SetField(fieldName, this.texture); } } this.isDeserialized = true; } }
/// <summary> /// Sets the texture's data. /// </summary> /// <param name="level">The mipmap level for which to set data.</param> /// <param name="rect">A rectangle describing the position and size of the data to set, or <see langword="null"/> to set the entire texture.</param> /// <param name="data">A pointer to the data to set.</param> /// <param name="offset">The index of the first element to set.</param> /// <param name="count">The number of elements to set.</param> /// <param name="stride">The number of elements in one row of data, or zero to use the width of <paramref name="rect"/>.</param> /// <param name="format">The format of the data being set.</param> /// <param name="origin">A <see cref="SetDataOrigin"/> value specifying the origin of the texture data in <paramref name="data"/>.</param> public abstract void SetData(Int32 level, Rectangle?rect, IntPtr data, Int32 offset, Int32 count, Int32 stride, TextureDataFormat format, SetDataOrigin origin = SetDataOrigin.TopLeft);