/// <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
        }
Beispiel #3
0
        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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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;
            }
        }
Beispiel #12
0
 /// <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);