/*
** Copyright 2011, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
package com.android.glesv2debugger;
import com.google.protobuf.ByteString;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class MessageProcessor {
static void showError(final String message) {
// need to call SWT from UI thread
MessageDialog.openError(null, "MessageProcessor", message);
}
/**
* data layout: uint32 total decompressed length, (chunks: uint32 chunk
* decompressed size, uint32 chunk compressed size, chunk data)+. 0 chunk
* compressed size means chunk is not compressed
*/
public static byte[] lzfDecompressChunks(final ByteString data) {
ByteBuffer in = data.asReadOnlyByteBuffer();
in.order(SampleView.targetByteOrder);
ByteBuffer out = ByteBuffer.allocate(in.getInt());
byte[] inChunk = new byte[0];
byte[] outChunk = new byte[0];
while (in.remaining() > 0) {
int decompressed = in.getInt();
int compressed = in.getInt();
if (decompressed > outChunk.length)
outChunk = new byte[decompressed];
if (compressed == 0) {
in.get(outChunk, 0, decompressed);
out.put(outChunk, 0, decompressed);
} else {
if (compressed > inChunk.length)
inChunk = new byte[compressed];
in.get(inChunk, 0, compressed);
int size = org.liblzf.CLZF
.lzf_decompress(inChunk, compressed, outChunk, outChunk.length);
assert size == decompressed;
out.put(outChunk, 0, size);
}
}
assert !out.hasRemaining();
return out.array();
}
/** same data layout as LZFDecompressChunks */
public static byte[] lzfCompressChunks(final byte[] in, final int inSize) {
byte[] chunk = new byte[256 * 1024]; // chunk size is arbitrary
final ByteBuffer out = ByteBuffer.allocate(4 + (inSize + chunk.length - 1)
/ chunk.length * (chunk.length + 4 * 2));
out.order(SampleView.targetByteOrder);
out.putInt(inSize);
for (int i = 0; i < inSize; i += chunk.length) {
int chunkIn = chunk.length;
if (i + chunkIn > inSize)
chunkIn = inSize - i;
final byte[] inChunk = java.util.Arrays.copyOfRange(in, i, i + chunkIn);
final int chunkOut = org.liblzf.CLZF
.lzf_compress(inChunk, chunkIn, chunk, chunk.length);
out.putInt(chunkIn);
out.putInt(chunkOut);
if (chunkOut == 0) // compressed bigger than chunk (uncompressed)
out.put(inChunk);
else
out.put(chunk, 0, chunkOut);
}
return Arrays.copyOf(out.array(), out.position());
}
/**
* returns new ref, which is also the decoded image; ref could be bigger
* than pixels, in which case the first pixels.length bytes form the image
*/
public static byte[] decodeReferencedImage(byte[] ref, byte[] pixels) {
if (ref.length < pixels.length)
ref = new byte[pixels.length];
for (int i = 0; i < pixels.length; i++)
ref[i] ^= pixels[i];
for (int i = pixels.length; i < ref.length; i++)
ref[i] = 0; // clear unused ref to maintain consistency
return ref;
}
public static ImageData receiveImage(int width, int height, int format,
int type, final ByteString data) {
assert width > 0 && height > 0;
int bpp = 0;
int redMask = 0, blueMask = 0, greenMask = 0;
switch (GLEnum.valueOf(type)) {
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
format = type;
break;
case GL_UNSIGNED_BYTE:
break;
default:
showError("unsupported texture type " + type);
return null;
}
switch (GLEnum.valueOf(format)) {
case GL_ALPHA:
case GL_LUMINANCE:
redMask = blueMask = greenMask = 0xff;
bpp = 8;
break;
case GL_LUMINANCE_ALPHA:
blueMask = 0xff;
redMask = 0xff00;
bpp = 16;
break;
case GL_RGB:
blueMask = 0xff;
greenMask = 0xff00;
redMask = 0xff0000;
bpp = 24;
break;
case GL_RGBA:
blueMask = 0xff00;
greenMask = 0xff0000;
redMask = 0xff000000;
bpp = 32;
break;
case GL_UNSIGNED_SHORT_5_6_5:
blueMask = ((1 << 5) - 1) << 0;
greenMask = ((1 << 6) - 1) << 5;
redMask = ((1 << 5) - 1) << 11;
bpp = 16;
break;
case GL_UNSIGNED_SHORT_4_4_4_4:
blueMask = ((1 << 4) - 1) << 4;
greenMask = ((1 << 4) - 1) << 8;
redMask = ((1 << 4) - 1) << 12;
bpp = 16;
break;
case GL_UNSIGNED_SHORT_5_5_5_1:
blueMask = ((1 << 5) - 1) << 1;
greenMask = ((1 << 5) - 1) << 6;
redMask = ((1 << 5) - 1) << 11;
bpp = 16;
break;
default:
showError("unsupported texture format: " + format);
return null;
}
byte[] pixels = lzfDecompressChunks(data);
assert pixels.length == width * height * (bpp / 8);
PaletteData palette = new PaletteData(redMask, greenMask, blueMask);
return new ImageData(width, height, bpp, palette, 1, pixels);
}
}