ETC1Util.java revision 8af9649d44745adba8be4db4e96af053ba32f2c5
15f7643150411b16e71bc012c6ceb2d865c0a34d4Ted Kremenek/* 2cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * Copyright 2009 Google Inc. 3cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * 4cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * you may not use this file except in compliance with the License. 6cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * You may obtain a copy of the License at 7cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * 8cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * http://www.apache.org/licenses/LICENSE-2.0 9cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * 10cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * Unless required by applicable law or agreed to in writing, software 11cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * distributed under the License is distributed on an "AS IS" BASIS, 12cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * See the License for the specific language governing permissions and 149b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek * limitations under the License. 15cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu */ 16337e4dbc6859589b8878146a88bebf754e916702Ted Kremenek 17563ea2335d7d0df44bbfe8941f64523e8af1fc14Jordan Rosepackage android.opengl; 1855fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth 1955fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruthimport java.io.IOException; 2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruthimport java.io.InputStream; 21cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xuimport java.io.OutputStream; 22cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xuimport java.nio.Buffer; 239ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekimport java.nio.ByteBuffer; 24cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xuimport java.nio.ByteOrder; 25eea72a925f294225391ecec876a342771c09b635Ted Kremenek 26eea72a925f294225391ecec876a342771c09b635Ted Kremenek/** 27eea72a925f294225391ecec876a342771c09b635Ted Kremenek * Utility methods for using ETC1 compressed textures. 2866c486f275531df6362b3511fc3af6563561801bTed Kremenek * 296a835dddf45922e71a87637fdfac0863de65123cTed Kremenek */ 308bef8238181a30e52dea380789a7e2d760eac532Ted Kremenekpublic class ETC1Util { 315eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek /** 32cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * Convenience method to load an ETC1 texture whether or not the active OpenGL context 33c210cb7a358d14cdd93b58562f33ff5ed2d895c1Jordan Rose * supports the ETC1 texture compression format. 34cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu * @param target the texture target. 356ebea89be233eaba5e29de8cf3524ad150c860bbJordan Rose * @param level the texture level 366ebea89be233eaba5e29de8cf3524ad150c860bbJordan Rose * @param border the border size. Typically 0. 37eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose * @param fallbackFormat the format to use if ETC1 texture compression is not supported. 38eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose * Must be GL_RGB. 396ebea89be233eaba5e29de8cf3524ad150c860bbJordan Rose * @param fallbackType the type to use if ETC1 texture compression is not supported. 40eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose * Can be either GL_UNSIGNED_SHORT_5_6_5, which implies 16-bits-per-pixel, 41eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose * or GL_UNSIGNED_BYTE, which implies 24-bits-per-pixel. 42eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose * @param input the input stream containing an ETC1 texture in PKM format. 43eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose * @throws IOException 44eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose */ 45cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu public static void loadTexture(int target, int level, int border, 46eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose int fallbackFormat, int fallbackType, InputStream input) 47eafb5c694cc5d165149fcb9453bc9355fb0d44a5Jordan Rose throws IOException { 485e5440ba9c135f523f72e7e7c5da59d390d697c5Jordan Rose loadTexture(target, level, border, fallbackFormat, fallbackType, createTexture(input)); 49cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu } 50cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu 51a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose /** 52a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * Convenience method to load an ETC1 texture whether or not the active OpenGL context 53bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose * supports the ETC1 texture compression format. 54a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * @param target the texture target. 55a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * @param level the texture level 56a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * @param border the border size. Typically 0. 57a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * @param fallbackFormat the format to use if ETC1 texture compression is not supported. 58a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * Must be GL_RGB. 59a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * @param fallbackType the type to use if ETC1 texture compression is not supported. 60a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * Can be either GL_UNSIGNED_SHORT_5_6_5, which implies 16-bits-per-pixel, 61a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * or GL_UNSIGNED_BYTE, which implies 24-bits-per-pixel. 62a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * @param texture the ETC1 to load. 63a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose */ 64a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose public static void loadTexture(int target, int level, int border, 65a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose int fallbackFormat, int fallbackType, ETC1Texture texture) { 66a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose if (fallbackFormat != GLES10.GL_RGB) { 67a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose throw new IllegalArgumentException("fallbackFormat must be GL_RGB"); 68a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose } 69bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose if (! (fallbackType == GLES10.GL_UNSIGNED_SHORT_5_6_5 70bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose || fallbackType == GLES10.GL_UNSIGNED_BYTE)) { 71bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose throw new IllegalArgumentException("Unsupported fallbackType"); 72bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose } 73bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose 74bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int width = texture.getWidth(); 75bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int height = texture.getHeight(); 76bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose Buffer data = texture.getData(); 77a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose if (isETC1Supported()) { 78a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose int imageSize = data.remaining(); 79dc84cd5efdd3430efb22546b4ac656aa0540b210David Blaikie GLES10.glCompressedTexImage2D(target, level, ETC1.ETC1_RGB8_OES, width, height, 80bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose border, imageSize, data); 81a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose } else { 82a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose boolean useShorts = fallbackType != GLES10.GL_UNSIGNED_BYTE; 83bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int pixelSize = useShorts ? 2 : 3; 84a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose int stride = pixelSize * width; 85a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose ByteBuffer decodedData = ByteBuffer.allocateDirect(stride*height) 86bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose .order(ByteOrder.nativeOrder()); 87a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose ETC1.decodeImage(data, decodedData, width, height, pixelSize, stride); 88bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose GLES10.glTexImage2D(target, level, fallbackFormat, width, height, border, 89bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose fallbackFormat, fallbackType, decodedData); 90bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose } 91a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose } 92a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose 93a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose /** 94a8d937e4bdd39cdf503f77454e9dc4c9c730a9f7Jordan Rose * Check if ETC1 texture compression is supported by the active OpenGL ES context. 95bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose * @return true if the active OpenGL ES context supports ETC1 texture compression. 96bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose */ 97bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose public static boolean isETC1Supported() { 98bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int[] results = new int[20]; 99362a31cacc19764f3630928a9e4779af2576e074Jordan Rose GLES10.glGetIntegerv(GLES10.GL_NUM_COMPRESSED_TEXTURE_FORMATS, results, 0); 1005fe98728dca1f3a7a378ce1a21984a0f8a0c0b8bTed Kremenek int numFormats = results[0]; 1015fe98728dca1f3a7a378ce1a21984a0f8a0c0b8bTed Kremenek if (numFormats > results.length) { 102888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose results = new int[numFormats]; 103075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose } 104075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose GLES10.glGetIntegerv(GLES10.GL_COMPRESSED_TEXTURE_FORMATS, results, 0); 105888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose for (int i = 0; i < numFormats; i++) { 106bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose if (results[i] == ETC1.ETC1_RGB8_OES) { 107888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose return true; 108888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 109888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 110075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose return false; 111075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose } 11266c486f275531df6362b3511fc3af6563561801bTed Kremenek 11366c486f275531df6362b3511fc3af6563561801bTed Kremenek /** 11466c486f275531df6362b3511fc3af6563561801bTed Kremenek * A utility class encapsulating a compressed ETC1 texture. 115075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose */ 116075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose public static class ETC1Texture { 117b07805485c603be3d8011f72611465324c9e664bDavid Blaikie public ETC1Texture(int width, int height, ByteBuffer data) { 118b07805485c603be3d8011f72611465324c9e664bDavid Blaikie mWidth = width; 119e460c46c5d602f65354cab0879c458890273591cJordan Rose mHeight = height; 120e460c46c5d602f65354cab0879c458890273591cJordan Rose mData = data; 121e460c46c5d602f65354cab0879c458890273591cJordan Rose } 122e460c46c5d602f65354cab0879c458890273591cJordan Rose 123e460c46c5d602f65354cab0879c458890273591cJordan Rose /** 124e460c46c5d602f65354cab0879c458890273591cJordan Rose * Get the width of the texture in pixels. 125e460c46c5d602f65354cab0879c458890273591cJordan Rose * @return the width of the texture in pixels. 126e460c46c5d602f65354cab0879c458890273591cJordan Rose */ 127e460c46c5d602f65354cab0879c458890273591cJordan Rose public int getWidth() { return mWidth; } 128e460c46c5d602f65354cab0879c458890273591cJordan Rose 129e460c46c5d602f65354cab0879c458890273591cJordan Rose /** 130bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose * Get the height of the texture in pixels. 131e460c46c5d602f65354cab0879c458890273591cJordan Rose * @return the width of the texture in pixels. 132e460c46c5d602f65354cab0879c458890273591cJordan Rose */ 133e460c46c5d602f65354cab0879c458890273591cJordan Rose public int getHeight() { return mHeight; } 134e460c46c5d602f65354cab0879c458890273591cJordan Rose 135e460c46c5d602f65354cab0879c458890273591cJordan Rose /** 136e460c46c5d602f65354cab0879c458890273591cJordan Rose * Get the compressed data of the texture. 137e460c46c5d602f65354cab0879c458890273591cJordan Rose * @return the texture data. 138e460c46c5d602f65354cab0879c458890273591cJordan Rose */ 1393a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose public ByteBuffer getData() { return mData; } 140b07805485c603be3d8011f72611465324c9e664bDavid Blaikie 141b07805485c603be3d8011f72611465324c9e664bDavid Blaikie private int mWidth; 1423a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose private int mHeight; 1433a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose private ByteBuffer mData; 1443a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose } 1453a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose 1463a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose /** 1473a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose * Create a new ETC1Texture from an input stream containing a PKM formatted compressed texture. 1483a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose * @param input an input stream containing a PKM formatted compressed texture. 1493a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose * @return an ETC1Texture read from the input stream. 1503a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose * @throws IOException 151e460c46c5d602f65354cab0879c458890273591cJordan Rose */ 1523a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose public static ETC1Texture createTexture(InputStream input) throws IOException { 1533a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose int width = 0; 154e460c46c5d602f65354cab0879c458890273591cJordan Rose int height = 0; 1553a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose byte[] ioBuffer = new byte[4096]; 1563a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose { 1573a0a9e3e8bbaa45f3ca22b1e20b3beaac0f5861eJordan Rose if (input.read(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE) != ETC1.ETC_PKM_HEADER_SIZE) { 158075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose throw new IOException("Unable to read PKM file header."); 159075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose } 160075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose ByteBuffer headerBuffer = ByteBuffer.allocateDirect(ETC1.ETC_PKM_HEADER_SIZE) 161c210cb7a358d14cdd93b58562f33ff5ed2d895c1Jordan Rose .order(ByteOrder.nativeOrder()); 162c210cb7a358d14cdd93b58562f33ff5ed2d895c1Jordan Rose headerBuffer.put(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE).position(0); 163c210cb7a358d14cdd93b58562f33ff5ed2d895c1Jordan Rose if (!ETC1.isValid(headerBuffer)) { 164c210cb7a358d14cdd93b58562f33ff5ed2d895c1Jordan Rose throw new IOException("Not a PKM file."); 165c210cb7a358d14cdd93b58562f33ff5ed2d895c1Jordan Rose } 166c210cb7a358d14cdd93b58562f33ff5ed2d895c1Jordan Rose width = ETC1.getWidth(headerBuffer); 167075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose height = ETC1.getHeight(headerBuffer); 168888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 169888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose int encodedSize = ETC1.getEncodedDataSize(width, height); 170888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose ByteBuffer dataBuffer = ByteBuffer.allocateDirect(encodedSize).order(ByteOrder.nativeOrder()); 171888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose for (int i = 0; i < encodedSize; ) { 172888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose int chunkSize = Math.min(ioBuffer.length, encodedSize - i); 173888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose if (input.read(ioBuffer, 0, chunkSize) != chunkSize) { 174888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose throw new IOException("Unable to read PKM file data."); 175888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 176075f6fbcb4d858c09e9b138f8dc10d8d3d43d935Jordan Rose dataBuffer.put(ioBuffer, 0, chunkSize); 177888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose i += chunkSize; 178888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 179888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose dataBuffer.position(0); 180888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose return new ETC1Texture(width, height, dataBuffer); 181888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 1824411b423e91da0a2c879b70c0222aeba35f72044Jordan Rose 1834411b423e91da0a2c879b70c0222aeba35f72044Jordan Rose /** 1844411b423e91da0a2c879b70c0222aeba35f72044Jordan Rose * Helper function that compresses an image into an ETC1Texture. 1854411b423e91da0a2c879b70c0222aeba35f72044Jordan Rose * @param input a native order direct buffer containing the image data 186e460c46c5d602f65354cab0879c458890273591cJordan Rose * @param width the width of the image in pixels 187888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose * @param height the height of the image in pixels 188888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose * @param pixelSize the size of a pixel in bytes (2 or 3) 189888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose * @param stride the width of a line of the image in bytes 190888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose * @return the ETC1 texture. 191888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose */ 192d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose public static ETC1Texture compressTexture(Buffer input, int width, int height, int pixelSize, int stride){ 193d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose int encodedImageSize = ETC1.getEncodedDataSize(width, height); 194d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose ByteBuffer compressedImage = ByteBuffer.allocateDirect(encodedImageSize). 195cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu order(ByteOrder.nativeOrder()); 196362a31cacc19764f3630928a9e4779af2576e074Jordan Rose ETC1.encodeImage(input, width, height, 3, stride, compressedImage); 197362a31cacc19764f3630928a9e4779af2576e074Jordan Rose return new ETC1Texture(width, height, compressedImage); 19896479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose } 19996479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose 200d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose /** 2015fe98728dca1f3a7a378ce1a21984a0f8a0c0b8bTed Kremenek * Helper function that writes an ETC1Texture to an output stream formatted as a PKM file. 202bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose * @param texture the input texture. 203bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose * @param output the stream to write the formatted texture data to. 204bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose * @throws IOException 205bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose */ 206bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose public static void writeTexture(ETC1Texture texture, OutputStream output) throws IOException { 207bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose ByteBuffer dataBuffer = texture.getData(); 208bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int originalPosition = dataBuffer.position(); 209bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose try { 210bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int width = texture.getWidth(); 211bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int height = texture.getHeight(); 212bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose ByteBuffer header = ByteBuffer.allocateDirect(ETC1.ETC_PKM_HEADER_SIZE).order(ByteOrder.nativeOrder()); 213bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose ETC1.formatHeader(header, width, height); 214bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose byte[] ioBuffer = new byte[4096]; 215bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose header.get(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE); 216bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose output.write(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE); 217bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose int encodedSize = ETC1.getEncodedDataSize(width, height); 2185fe98728dca1f3a7a378ce1a21984a0f8a0c0b8bTed Kremenek for (int i = 0; i < encodedSize; ) { 21996479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose int chunkSize = Math.min(ioBuffer.length, encodedSize - i); 220bc403861bc4e6f7ad1371e9e129f0f25b38b3a9aJordan Rose dataBuffer.get(ioBuffer, 0, chunkSize); 221d563d3fb73879df7147b8a5302c3bf0e1402ba18Jordan Rose output.write(ioBuffer, 0, chunkSize); 22296479da6ad9d921d875e7be29fe1bfa127be8069Jordan Rose i += chunkSize; 223cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu } 224cb7464ab402d057849dda9749d62a62d86c35ab8Zhongxing Xu } finally { 225888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose dataBuffer.position(originalPosition); 226888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 227888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose } 228200fa2e70d52ae6d620e81cd45536071fdde70c0Jordan Rose} 229888c90ac0ef6baf7d47e86cf5cc4715707d223b1Jordan Rose