Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6276fdd authored by Jack Palevich's avatar Jack Palevich
Browse files

A library for encoding and decoding ETC1 textures.

The ETC1 compressed texture format is commonly
supported by OpenGL ES 2.0-capable devices.
parent 8eb3ea65
Loading
Loading
Loading
Loading
+395 −0
Original line number Diff line number Diff line
@@ -88168,6 +88168,401 @@
</package>
<package name="android.opengl"
>
<class name="ETC1"
 extends="java.lang.Object"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="ETC1"
 type="android.opengl.ETC1"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</constructor>
<method name="decodeBlock"
 return="void"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="in" type="java.nio.Buffer">
</parameter>
<parameter name="out" type="java.nio.Buffer">
</parameter>
</method>
<method name="decodeImage"
 return="void"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="in" type="java.nio.Buffer">
</parameter>
<parameter name="out" type="java.nio.Buffer">
</parameter>
<parameter name="width" type="int">
</parameter>
<parameter name="height" type="int">
</parameter>
<parameter name="pixelSize" type="int">
</parameter>
<parameter name="stride" type="int">
</parameter>
</method>
<method name="encodeBlock"
 return="void"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="in" type="java.nio.Buffer">
</parameter>
<parameter name="validPixelMask" type="int">
</parameter>
<parameter name="out" type="java.nio.Buffer">
</parameter>
</method>
<method name="encodeImage"
 return="void"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="in" type="java.nio.Buffer">
</parameter>
<parameter name="width" type="int">
</parameter>
<parameter name="height" type="int">
</parameter>
<parameter name="pixelSize" type="int">
</parameter>
<parameter name="stride" type="int">
</parameter>
<parameter name="out" type="java.nio.Buffer">
</parameter>
</method>
<method name="formatHeader"
 return="void"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="header" type="java.nio.Buffer">
</parameter>
<parameter name="width" type="int">
</parameter>
<parameter name="height" type="int">
</parameter>
</method>
<method name="getEncodedDataSize"
 return="int"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="width" type="int">
</parameter>
<parameter name="height" type="int">
</parameter>
</method>
<method name="getHeight"
 return="int"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="header" type="java.nio.Buffer">
</parameter>
</method>
<method name="getWidth"
 return="int"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="header" type="java.nio.Buffer">
</parameter>
</method>
<method name="isValid"
 return="boolean"
 abstract="false"
 native="true"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="header" type="java.nio.Buffer">
</parameter>
</method>
<field name="DECODED_BLOCK_SIZE"
 type="int"
 transient="false"
 volatile="false"
 value="48"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="ENCODED_BLOCK_SIZE"
 type="int"
 transient="false"
 volatile="false"
 value="8"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="ETC1_RGB8_OES"
 type="int"
 transient="false"
 volatile="false"
 value="36196"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="ETC_PKM_HEADER_SIZE"
 type="int"
 transient="false"
 volatile="false"
 value="16"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
</class>
<class name="ETC1Util"
 extends="java.lang.Object"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="ETC1Util"
 type="android.opengl.ETC1Util"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</constructor>
<method name="compressTexture"
 return="android.opengl.ETC1Util.ETC1Texture"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="input" type="java.nio.Buffer">
</parameter>
<parameter name="width" type="int">
</parameter>
<parameter name="height" type="int">
</parameter>
<parameter name="pixelSize" type="int">
</parameter>
<parameter name="stride" type="int">
</parameter>
</method>
<method name="createTexture"
 return="android.opengl.ETC1Util.ETC1Texture"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="input" type="java.io.InputStream">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="isETC1Supported"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="loadTexture"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="target" type="int">
</parameter>
<parameter name="level" type="int">
</parameter>
<parameter name="border" type="int">
</parameter>
<parameter name="fallbackFormat" type="int">
</parameter>
<parameter name="fallbackType" type="int">
</parameter>
<parameter name="input" type="java.io.InputStream">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="loadTexture"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="target" type="int">
</parameter>
<parameter name="level" type="int">
</parameter>
<parameter name="border" type="int">
</parameter>
<parameter name="fallbackFormat" type="int">
</parameter>
<parameter name="fallbackType" type="int">
</parameter>
<parameter name="texture" type="android.opengl.ETC1Util.ETC1Texture">
</parameter>
</method>
<method name="writeTexture"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="texture" type="android.opengl.ETC1Util.ETC1Texture">
</parameter>
<parameter name="output" type="java.io.OutputStream">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</class>
<class name="ETC1Util.ETC1Texture"
 extends="java.lang.Object"
 abstract="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="ETC1Util.ETC1Texture"
 type="android.opengl.ETC1Util.ETC1Texture"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="width" type="int">
</parameter>
<parameter name="height" type="int">
</parameter>
<parameter name="data" type="java.nio.ByteBuffer">
</parameter>
</constructor>
<method name="getData"
 return="java.nio.ByteBuffer"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getHeight"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="getWidth"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
</class>
<class name="GLDebugHelper"
 extends="java.lang.Object"
 abstract="false"
+1 −0
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ LOCAL_SHARED_LIBRARIES := \
	libEGL \
	libGLESv1_CM \
	libGLESv2 \
	libETC1 \
	libhardware \
	libhardware_legacy \
	libsonivox \
+309 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <dlfcn.h>

#include <GLES/gl.h>
#include <ETC1/etc1.h>

#include <core/SkBitmap.h>

@@ -39,6 +40,7 @@ namespace android {

static jclass gIAEClass;
static jclass gUOEClass;
static jclass gAIOOBEClass;

static inline
void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
@@ -711,6 +713,297 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
    return 0;
}

/*
 * ETC1 methods.
 */

static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
static jfieldID positionID;
static jfieldID limitID;
static jfieldID elementSizeShiftID;

/* Cache method IDs each time the class is loaded. */

static void
nativeClassInitBuffer(JNIEnv *_env)
{
    jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);

    jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);

    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
            "getBasePointer", "(Ljava/nio/Buffer;)J");
    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
    positionID = _env->GetFieldID(bufferClass, "position", "I");
    limitID = _env->GetFieldID(bufferClass, "limit", "I");
    elementSizeShiftID =
        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
}

static void *
getPointer(JNIEnv *_env, jobject buffer, jint *remaining)
{
    jint position;
    jint limit;
    jint elementSizeShift;
    jlong pointer;
    jint offset;
    void *data;

    position = _env->GetIntField(buffer, positionID);
    limit = _env->GetIntField(buffer, limitID);
    elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
    *remaining = (limit - position) << elementSizeShift;
    pointer = _env->CallStaticLongMethod(nioAccessClass,
            getBasePointerID, buffer);
    if (pointer != 0L) {
        return (void *) (jint) pointer;
    }
    return NULL;
}

class BufferHelper {
public:
    BufferHelper(JNIEnv *env, jobject buffer) {
        mEnv = env;
        mBuffer = buffer;
        mData = NULL;
        mRemaining = 0;
    }

    bool checkPointer(const char* errorMessage) {
        if (mBuffer) {
            mData = getPointer(mEnv, mBuffer, &mRemaining);
            if (mData == NULL) {
                mEnv->ThrowNew(gIAEClass, errorMessage);
            }
            return mData != NULL;
        } else {
            mEnv->ThrowNew(gIAEClass, errorMessage);
            return false;
        }
    }

    inline void* getData() {
        return mData;
    }

    inline jint remaining() {
        return mRemaining;
    }

private:
    JNIEnv* mEnv;
    jobject mBuffer;
    void* mData;
    jint mRemaining;
};

/**
 * Encode a block of pixels.
 *
 * @param in a pointer to a ETC1_DECODED_BLOCK_SIZE array of bytes that represent a
 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
 * value of pixel (x, y).
 *
 * @param validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
 * the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
 *
 * @param out an ETC1 compressed version of the data.
 *
 */
static void etc1_encodeBlock(JNIEnv *env, jclass clazz,
        jobject in, jint validPixelMask, jobject out) {
    if (validPixelMask < 0 || validPixelMask > 15) {
        env->ThrowNew(gIAEClass, "validPixelMask");
        return;
    }
    BufferHelper inB(env, in);
    BufferHelper outB(env, out);
    if (inB.checkPointer("in") && outB.checkPointer("out")) {
        if (inB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
            env->ThrowNew(gIAEClass, "in's remaining data < DECODED_BLOCK_SIZE");
        } else if (outB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
            env->ThrowNew(gIAEClass, "out's remaining data < ENCODED_BLOCK_SIZE");
        } else {
            etc1_encode_block((etc1_byte*) inB.getData(), validPixelMask,
                    (etc1_byte*) outB.getData());
        }
    }
}

/**
 * Decode a block of pixels.
 *
 * @param in an ETC1 compressed version of the data.
 *
 * @param out a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
 * 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
 * value of pixel (x, y).
 */
static void etc1_decodeBlock(JNIEnv *env, jclass clazz,
        jobject in, jobject out){
    BufferHelper inB(env, in);
    BufferHelper outB(env, out);
    if (inB.checkPointer("in") && outB.checkPointer("out")) {
        if (inB.remaining() < ETC1_ENCODED_BLOCK_SIZE) {
            env->ThrowNew(gIAEClass, "in's remaining data < ENCODED_BLOCK_SIZE");
        } else if (outB.remaining() < ETC1_DECODED_BLOCK_SIZE) {
            env->ThrowNew(gIAEClass, "out's remaining data < DECODED_BLOCK_SIZE");
        } else {
            etc1_decode_block((etc1_byte*) inB.getData(),
                    (etc1_byte*) outB.getData());
        }
    }
}

/**
 * Return the size of the encoded image data (does not include size of PKM header).
 */
static jint etc1_getEncodedDataSize(JNIEnv *env, jclass clazz,
        jint width, jint height) {
    return etc1_get_encoded_data_size(width, height);
}

/**
 * Encode an entire image.
 * @param in pointer to the image data. Formatted such that
 *           pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
 * @param out pointer to encoded data. Must be large enough to store entire encoded image.
 */
static void etc1_encodeImage(JNIEnv *env, jclass clazz,
        jobject in, jint width, jint height,
        jint pixelSize, jint stride, jobject out) {
    if (pixelSize < 2 || pixelSize > 3) {
        env->ThrowNew(gIAEClass, "pixelSize must be 2 or 3");
        return;
    }
    BufferHelper inB(env, in);
    BufferHelper outB(env, out);
    if (inB.checkPointer("in") && outB.checkPointer("out")) {
        jint imageSize = stride * height;
        jint encodedImageSize = etc1_get_encoded_data_size(width, height);
        if (inB.remaining() < imageSize) {
            env->ThrowNew(gIAEClass, "in's remaining data < image size");
        } else if (outB.remaining() < encodedImageSize) {
            env->ThrowNew(gIAEClass, "out's remaining data < encoded image size");
        } else {
            int result = etc1_encode_image((etc1_byte*) inB.getData(),
                    width, height, pixelSize,
                    stride,
                    (etc1_byte*) outB.getData());
        }
    }
}

/**
 * Decode an entire image.
 * @param in the encoded data.
 * @param out pointer to the image data. Will be written such that
 *            pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
 *            large enough to store entire image.
 */
static void etc1_decodeImage(JNIEnv *env, jclass clazz,
        jobject  in, jobject out,
        jint width, jint height,
        jint pixelSize, jint stride) {
    if (pixelSize < 2 || pixelSize > 3) {
        env->ThrowNew(gIAEClass, "pixelSize must be 2 or 3");
        return;
    }
    BufferHelper inB(env, in);
    BufferHelper outB(env, out);
    if (inB.checkPointer("in") && outB.checkPointer("out")) {
        jint imageSize = stride * height;
        jint encodedImageSize = etc1_get_encoded_data_size(width, height);
        if (inB.remaining() < encodedImageSize) {
            env->ThrowNew(gIAEClass, "in's remaining data < encoded image size");
        } else if (outB.remaining() < imageSize) {
            env->ThrowNew(gIAEClass, "out's remaining data < image size");
        } else {
            int result = etc1_decode_image((etc1_byte*) inB.getData(),
                    (etc1_byte*) outB.getData(),
                    width, height, pixelSize,
                    stride);
        }
    }
}

/**
 * Format a PKM header
 */
static void etc1_formatHeader(JNIEnv *env, jclass clazz,
        jobject header, jint width, jint height) {
    BufferHelper headerB(env, header);
    if (headerB.checkPointer("header") ){
        if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
            env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
        } else {
            etc1_pkm_format_header((etc1_byte*) headerB.getData(), width, height);
        }
    }
}

/**
 * Check if a PKM header is correctly formatted.
 */
static jboolean etc1_isValid(JNIEnv *env, jclass clazz,
        jobject header) {
    jboolean result = false;
    BufferHelper headerB(env, header);
    if (headerB.checkPointer("header") ){
        if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
            env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
        } else {
            result = etc1_pkm_is_valid((etc1_byte*) headerB.getData());
        }
    }
    return result;
}

/**
 * Read the image width from a PKM header
 */
static jint etc1_getWidth(JNIEnv *env, jclass clazz,
        jobject header) {
    jint result = 0;
    BufferHelper headerB(env, header);
    if (headerB.checkPointer("header") ){
        if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
            env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
        } else {
            result = etc1_pkm_get_width((etc1_byte*) headerB.getData());
        }
    }
    return result;
}

/**
 * Read the image height from a PKM header
 */
static int etc1_getHeight(JNIEnv *env, jclass clazz,
        jobject header) {
    jint result = 0;
    BufferHelper headerB(env, header);
    if (headerB.checkPointer("header") ){
        if (headerB.remaining() < ETC_PKM_HEADER_SIZE) {
            env->ThrowNew(gIAEClass, "header's remaining data < ETC_PKM_HEADER_SIZE");
        } else {
            result = etc1_pkm_get_height((etc1_byte*) headerB.getData());
        }
    }
    return result;
}

/*
 * JNI registration
 */
@@ -721,6 +1014,8 @@ lookupClasses(JNIEnv* env) {
            env->FindClass("java/lang/IllegalArgumentException"));
    gUOEClass = (jclass) env->NewGlobalRef(
            env->FindClass("java/lang/UnsupportedOperationException"));
    gAIOOBEClass = (jclass) env->NewGlobalRef(
            env->FindClass("java/lang/ArrayIndexOutOfBoundsException"));
}

static JNINativeMethod gMatrixMethods[] = {
@@ -742,6 +1037,18 @@ static JNINativeMethod gUtilsMethods[] = {
    { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
};

static JNINativeMethod gEtc1Methods[] = {
    { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
    { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
    { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
    { "encodeImage", "(Ljava/nio/Buffer;IIIILjava/nio/Buffer;)V", (void*) etc1_encodeImage },
    { "decodeImage", "(Ljava/nio/Buffer;Ljava/nio/Buffer;IIII)V", (void*) etc1_decodeImage },
    { "formatHeader", "(Ljava/nio/Buffer;II)V", (void*) etc1_formatHeader },
    { "isValid", "(Ljava/nio/Buffer;)Z", (void*) etc1_isValid },
    { "getWidth", "(Ljava/nio/Buffer;)I", (void*) etc1_getWidth },
    { "getHeight", "(Ljava/nio/Buffer;)I", (void*) etc1_getHeight },
};

typedef struct _ClassRegistrationInfo {
    const char* classPath;
    JNINativeMethod* methods;
@@ -752,11 +1059,13 @@ static ClassRegistrationInfo gClasses[] = {
        {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
        {"android/opengl/Visibility", gVisiblityMethods, NELEM(gVisiblityMethods)},
        {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
        {"android/opengl/ETC1", gEtc1Methods, NELEM(gEtc1Methods)},
};

int register_android_opengl_classes(JNIEnv* env)
{
    lookupClasses(env);
    nativeClassInitBuffer(env);
    int result = 0;
    for (int i = 0; i < NELEM(gClasses); i++) {
        ClassRegistrationInfo* cri = &gClasses[i];
+106 −0
Original line number Diff line number Diff line
// Copyright 2009 Google Inc.
//
// 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.

#ifndef __etc1_h__
#define __etc1_h__

#define ETC1_ENCODED_BLOCK_SIZE 8
#define ETC1_DECODED_BLOCK_SIZE 48

#ifndef ETC1_RGB8_OES
#define ETC1_RGB8_OES 0x8D64
#endif

typedef unsigned char etc1_byte;
typedef int etc1_bool;
typedef unsigned int etc1_uint32;

#ifdef __cplusplus
extern "C" {
#endif

// Encode a block of pixels.
//
// pIn is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
// value of pixel (x, y).
//
// validPixelMask is a 16-bit mask where bit (1 << (x + y * 4)) indicates whether
// the corresponding (x,y) pixel is valid. Invalid pixel color values are ignored when compressing.
//
// pOut is an ETC1 compressed version of the data.

void etc1_encode_block(const etc1_byte* pIn, etc1_uint32 validPixelMask, etc1_byte* pOut);

// Decode a block of pixels.
//
// pIn is an ETC1 compressed version of the data.
//
// pOut is a pointer to a ETC_DECODED_BLOCK_SIZE array of bytes that represent a
// 4 x 4 square of 3-byte pixels in form R, G, B. Byte (3 * (x + 4 * y) is the R
// value of pixel (x, y).

void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut);

// Return the size of the encoded image data (does not include size of PKM header).

etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height);

// Encode an entire image.
// pIn - pointer to the image data. Formatted such that
//       pixel (x,y) is at pIn + pixelSize * x + stride * y;
// pOut - pointer to encoded data. Must be large enough to store entire encoded image.
// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image.
// returns non-zero if there is an error.

int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height,
        etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut);

// Decode an entire image.
// pIn - pointer to encoded data.
// pOut - pointer to the image data. Will be written such that
//        pixel (x,y) is at pIn + pixelSize * x + stride * y. Must be
//        large enough to store entire image.
// pixelSize can be 2 or 3. 2 is an GL_UNSIGNED_SHORT_5_6_5 image, 3 is a GL_BYTE RGB image.
// returns non-zero if there is an error.

int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut,
        etc1_uint32 width, etc1_uint32 height,
        etc1_uint32 pixelSize, etc1_uint32 stride);

// Size of a PKM header, in bytes.

#define ETC_PKM_HEADER_SIZE 16

// Format a PKM header

void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height);

// Check if a PKM header is correctly formatted.

etc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader);

// Read the image width from a PKM header

etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader);

// Read the image height from a PKM header

etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader);

#ifdef __cplusplus
}
#endif

#endif
+137 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading