1a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/*
2c086ca1fa7cebc3e9a51abd4be4688346225c2e4Dan Bornstein * Copyright (C) 2009 The Android Open Source Project
3a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *
4a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * Licensed under the Apache License, Version 2.0 (the "License");
5a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * you may not use this file except in compliance with the License.
6a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * You may obtain a copy of the License at
7a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *
8c086ca1fa7cebc3e9a51abd4be4688346225c2e4Dan Bornstein *      http://www.apache.org/licenses/LICENSE-2.0
9a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *
10a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * Unless required by applicable law or agreed to in writing, software
11a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * distributed under the License is distributed on an "AS IS" BASIS,
12a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * See the License for the specific language governing permissions and
14a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * limitations under the License.
15a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich */
16a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
17a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichpackage android.opengl;
18a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
19a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichimport java.io.IOException;
20a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichimport java.io.InputStream;
21a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichimport java.io.OutputStream;
22a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichimport java.nio.Buffer;
23a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichimport java.nio.ByteBuffer;
24a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichimport java.nio.ByteOrder;
25a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
26a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/**
27a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * Utility methods for using ETC1 compressed textures.
28a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *
29a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich */
30a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichpublic class ETC1Util {
31a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    /**
32a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Convenience method to load an ETC1 texture whether or not the active OpenGL context
33a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * supports the ETC1 texture compression format.
34a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param target the texture target.
35a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param level the texture level
36a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param border the border size. Typically 0.
37a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param fallbackFormat the format to use if ETC1 texture compression is not supported.
38a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Must be GL_RGB.
39a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param fallbackType the type to use if ETC1 texture compression is not supported.
40a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Can be either GL_UNSIGNED_SHORT_5_6_5, which implies 16-bits-per-pixel,
41a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * or GL_UNSIGNED_BYTE, which implies 24-bits-per-pixel.
42a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param input the input stream containing an ETC1 texture in PKM format.
43a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @throws IOException
44a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     */
45a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    public static void loadTexture(int target, int level, int border,
46a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int fallbackFormat, int fallbackType, InputStream input)
47a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        throws IOException {
48a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        loadTexture(target, level, border, fallbackFormat, fallbackType, createTexture(input));
49a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
50a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
51a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    /**
52a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Convenience method to load an ETC1 texture whether or not the active OpenGL context
53a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * supports the ETC1 texture compression format.
54a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param target the texture target.
55a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param level the texture level
56a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param border the border size. Typically 0.
57a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param fallbackFormat the format to use if ETC1 texture compression is not supported.
58a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Must be GL_RGB.
59a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param fallbackType the type to use if ETC1 texture compression is not supported.
60a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Can be either GL_UNSIGNED_SHORT_5_6_5, which implies 16-bits-per-pixel,
61a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * or GL_UNSIGNED_BYTE, which implies 24-bits-per-pixel.
62a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param texture the ETC1 to load.
63a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     */
64a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    public static void loadTexture(int target, int level, int border,
65a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int fallbackFormat, int fallbackType, ETC1Texture texture) {
66a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        if (fallbackFormat != GLES10.GL_RGB) {
67a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            throw new IllegalArgumentException("fallbackFormat must be GL_RGB");
68a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
69a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        if (! (fallbackType == GLES10.GL_UNSIGNED_SHORT_5_6_5
70a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                || fallbackType == GLES10.GL_UNSIGNED_BYTE)) {
71a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            throw new IllegalArgumentException("Unsupported fallbackType");
72a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
73a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
74a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int width = texture.getWidth();
75a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int height = texture.getHeight();
76a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        Buffer data = texture.getData();
77a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        if (isETC1Supported()) {
78a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int imageSize = data.remaining();
79a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            GLES10.glCompressedTexImage2D(target, level, ETC1.ETC1_RGB8_OES, width, height,
80a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                    border, imageSize, data);
81a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        } else {
82a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            boolean useShorts = fallbackType != GLES10.GL_UNSIGNED_BYTE;
83a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int pixelSize = useShorts ? 2 : 3;
84a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int stride = pixelSize * width;
85a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            ByteBuffer decodedData = ByteBuffer.allocateDirect(stride*height)
86a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                .order(ByteOrder.nativeOrder());
87a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            ETC1.decodeImage(data, decodedData, width, height, pixelSize, stride);
88a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            GLES10.glTexImage2D(target, level, fallbackFormat, width, height, border,
89a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                    fallbackFormat, fallbackType, decodedData);
90a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
91a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
92a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
93a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    /**
94a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Check if ETC1 texture compression is supported by the active OpenGL ES context.
958af9649d44745adba8be4db4e96af053ba32f2c5Jack Palevich     * @return true if the active OpenGL ES context supports ETC1 texture compression.
96a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     */
97a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    public static boolean isETC1Supported() {
98a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int[] results = new int[20];
99a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        GLES10.glGetIntegerv(GLES10.GL_NUM_COMPRESSED_TEXTURE_FORMATS, results, 0);
100a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int numFormats = results[0];
101a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        if (numFormats > results.length) {
102a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            results = new int[numFormats];
103a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
104a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        GLES10.glGetIntegerv(GLES10.GL_COMPRESSED_TEXTURE_FORMATS, results, 0);
105a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        for (int i = 0; i < numFormats; i++) {
106a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            if (results[i] == ETC1.ETC1_RGB8_OES) {
107a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                return true;
108a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            }
109a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
110a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return false;
111a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
112a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
113a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    /**
114a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * A utility class encapsulating a compressed ETC1 texture.
115a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     */
116a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    public static class ETC1Texture {
117a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        public ETC1Texture(int width, int height, ByteBuffer data) {
118a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            mWidth = width;
119a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            mHeight = height;
120a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            mData = data;
121a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
122a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
123a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        /**
124a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         * Get the width of the texture in pixels.
125a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         * @return the width of the texture in pixels.
126a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         */
127a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        public int getWidth() { return mWidth; }
128a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
129a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        /**
130a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         * Get the height of the texture in pixels.
131a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         * @return the width of the texture in pixels.
132a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         */
133a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        public int getHeight() { return mHeight; }
134a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
135a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        /**
136a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         * Get the compressed data of the texture.
137a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         * @return the texture data.
138a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich         */
139a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        public ByteBuffer getData() { return mData; }
140a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
141a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        private int mWidth;
142a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        private int mHeight;
143a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        private ByteBuffer mData;
144a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
145a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
146a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    /**
147a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Create a new ETC1Texture from an input stream containing a PKM formatted compressed texture.
148a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param input an input stream containing a PKM formatted compressed texture.
149a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @return an ETC1Texture read from the input stream.
150a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @throws IOException
151a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     */
152a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    public static ETC1Texture createTexture(InputStream input) throws IOException {
153a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int width = 0;
154a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int height = 0;
155a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        byte[] ioBuffer = new byte[4096];
156a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        {
157a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            if (input.read(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE) != ETC1.ETC_PKM_HEADER_SIZE) {
158a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                throw new IOException("Unable to read PKM file header.");
159a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            }
160a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            ByteBuffer headerBuffer = ByteBuffer.allocateDirect(ETC1.ETC_PKM_HEADER_SIZE)
161a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                .order(ByteOrder.nativeOrder());
162a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            headerBuffer.put(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE).position(0);
163a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            if (!ETC1.isValid(headerBuffer)) {
164a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                throw new IOException("Not a PKM file.");
165a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            }
166a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            width = ETC1.getWidth(headerBuffer);
167a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            height = ETC1.getHeight(headerBuffer);
168a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
169a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int encodedSize = ETC1.getEncodedDataSize(width, height);
170a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        ByteBuffer dataBuffer = ByteBuffer.allocateDirect(encodedSize).order(ByteOrder.nativeOrder());
171a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        for (int i = 0; i < encodedSize; ) {
172a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int chunkSize = Math.min(ioBuffer.length, encodedSize - i);
173a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            if (input.read(ioBuffer, 0, chunkSize) != chunkSize) {
174a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                throw new IOException("Unable to read PKM file data.");
175a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            }
176a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            dataBuffer.put(ioBuffer, 0, chunkSize);
177a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            i += chunkSize;
178a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
179a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        dataBuffer.position(0);
180a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return new ETC1Texture(width, height, dataBuffer);
181a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
182a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
183a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    /**
184a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Helper function that compresses an image into an ETC1Texture.
185a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param input a native order direct buffer containing the image data
186a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param width the width of the image in pixels
187a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param height the height of the image in pixels
188a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param pixelSize the size of a pixel in bytes (2 or 3)
189a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param stride the width of a line of the image in bytes
190a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @return the ETC1 texture.
191a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     */
192a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    public static ETC1Texture compressTexture(Buffer input, int width, int height, int pixelSize, int stride){
193a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int encodedImageSize = ETC1.getEncodedDataSize(width, height);
194a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        ByteBuffer compressedImage = ByteBuffer.allocateDirect(encodedImageSize).
195a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            order(ByteOrder.nativeOrder());
196fc5e224e8dcc878606e47ba3d834be0a79498ac6Alex Sakhartchouk        ETC1.encodeImage(input, width, height, pixelSize, stride, compressedImage);
197a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return new ETC1Texture(width, height, compressedImage);
198a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
199a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
200a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    /**
201a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * Helper function that writes an ETC1Texture to an output stream formatted as a PKM file.
202a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param texture the input texture.
203a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @param output the stream to write the formatted texture data to.
204a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     * @throws IOException
205a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich     */
206a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    public static void writeTexture(ETC1Texture texture, OutputStream output) throws IOException {
207a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        ByteBuffer dataBuffer = texture.getData();
208a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        int originalPosition = dataBuffer.position();
209a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        try {
210a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int width = texture.getWidth();
211a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int height = texture.getHeight();
212a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            ByteBuffer header = ByteBuffer.allocateDirect(ETC1.ETC_PKM_HEADER_SIZE).order(ByteOrder.nativeOrder());
213a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            ETC1.formatHeader(header, width, height);
214a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            byte[] ioBuffer = new byte[4096];
215a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            header.get(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE);
216a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            output.write(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE);
217a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            int encodedSize = ETC1.getEncodedDataSize(width, height);
218a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            for (int i = 0; i < encodedSize; ) {
219a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                int chunkSize = Math.min(ioBuffer.length, encodedSize - i);
220a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                dataBuffer.get(ioBuffer, 0, chunkSize);
221a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                output.write(ioBuffer, 0, chunkSize);
222a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                i += chunkSize;
223a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            }
224a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        } finally {
225a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            dataBuffer.position(originalPosition);
226a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
227a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
228a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich}
229