void onDraw(SkCanvas* canvas) override { SkBitmap bm; SkString pkmFilename = GetResourcePath("mandrill_128.pkm"); SkAutoDataUnref fileData(SkData::NewFromFileName(pkmFilename.c_str())); if (nullptr == fileData) { SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n"); return; } SkAutoMalloc am(fileData->size()); memcpy(am.get(), fileData->data(), fileData->size()); int width, height; if (!slice_etc1_data(am.get(), &width, &height)) { SkDebugf("ETC1 Data is poorly formatted.\n"); return; } SkASSERT(124 == width); SkASSERT(124 == height); size_t dataSz = etc1_get_encoded_data_size(width, height) + ETC_PKM_HEADER_SIZE; SkAutoDataUnref nonPOTData(SkData::NewWithCopy(am.get(), dataSz)); if (!SkInstallDiscardablePixelRef(nonPOTData, &bm)) { SkDebugf("Could not install discardable pixel ref.\n"); return; } canvas->drawBitmap(bm, 0, 0); }
JNIEXPORT jobject JNICALL Java_com_badlogic_gdx_graphics_glutils_ETC1_encodeImage (JNIEnv *env, jclass, jobject imageData, jint offset, jint width, jint height, jint pixelSize) { etc1_byte* imgPtr = (etc1_byte*)env->GetDirectBufferAddress(imageData) + offset; int compressedSize = etc1_get_encoded_data_size(width, height); etc1_byte* comprPtr = (etc1_byte*)malloc(compressedSize); etc1_encode_image(imgPtr, width, height, pixelSize, width * pixelSize, comprPtr); return env->NewDirectByteBuffer(comprPtr, compressedSize); }
JNIEXPORT jint JNICALL Java_com_badlogic_gdx_graphics_glutils_ETC1_getCompressedDataSize(JNIEnv* env, jclass clazz, jint width, jint height) { //@line:204 return etc1_get_encoded_data_size(width, height); }
static inline jobject wrapped_Java_com_badlogic_gdx_graphics_glutils_ETC1_encodeImage (JNIEnv* env, jclass clazz, jobject obj_imageData, jint offset, jint width, jint height, jint pixelSize, char* imageData) { //@line:260 int compressedSize = etc1_get_encoded_data_size(width, height); etc1_byte* compressedData = (etc1_byte*)malloc(compressedSize); etc1_encode_image((etc1_byte*)imageData + offset, width, height, pixelSize, width * pixelSize, compressedData); return env->NewDirectByteBuffer(compressedData, compressedSize); }
bool SkKTXFile::WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data, uint32_t width, uint32_t height) { // First thing's first, write out the magic identifier and endianness... if (!stream->write(KTX_FILE_IDENTIFIER, KTX_FILE_IDENTIFIER_SIZE)) { return false; } if (!stream->write(&kKTX_ENDIANNESS_CODE, 4)) { return false; } Header hdr; hdr.fGLType = 0; hdr.fGLTypeSize = 1; hdr.fGLFormat = 0; hdr.fGLInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8; hdr.fGLBaseInternalFormat = GR_GL_RGB; hdr.fPixelWidth = width; hdr.fPixelHeight = height; hdr.fNumberOfArrayElements = 0; hdr.fNumberOfFaces = 1; hdr.fNumberOfMipmapLevels = 1; // !FIXME! The spec suggests that we put KTXOrientation as a // key value pair in the header, but that means that we'd have to // pipe through the bitmap's orientation to properly do that. hdr.fBytesOfKeyValueData = 0; // Write the header if (!stream->write(&hdr, sizeof(hdr))) { return false; } // Write the size of the image data etc1_uint32 dataSize = etc1_get_encoded_data_size(width, height); if (!stream->write(&dataSize, 4)) { return false; } // Write the actual image data if (!stream->write(etc1Data, dataSize)) { return false; } return true; }
/** * Remove the last row and column of ETC1 blocks, effectively * making a texture that started as power of two into a texture * that is no longer power of two... */ bool slice_etc1_data(void *data, int* width, int* height) { // First, parse the data and get to it... etc1_byte *origData = reinterpret_cast<etc1_byte *>(data); if (!etc1_pkm_is_valid(origData)) { return false; } int origW = etc1_pkm_get_width(origData); int origH = etc1_pkm_get_height(origData); int blockWidth = (origW + 3) >> 2; int blockHeight = (origH + 3) >> 2; // Make sure that we have blocks to trim off.. if (blockWidth < 2 || blockHeight < 2) { return false; } int newWidth = (blockWidth - 1) << 2; int newHeight = (blockHeight - 1) << 2; size_t newDataSz = etc1_get_encoded_data_size(newWidth, newHeight) + ETC_PKM_HEADER_SIZE; SkAutoMalloc am(newDataSz); etc1_byte *newData = reinterpret_cast<etc1_byte *>(am.get()); etc1_pkm_format_header(newData, newWidth, newHeight); newData += ETC_PKM_HEADER_SIZE; origData += ETC_PKM_HEADER_SIZE; for (int j = 0; j < blockHeight - 1; ++j) { memcpy(newData, origData, (blockWidth - 1)*ETC1_ENCODED_BLOCK_SIZE); origData += blockWidth*ETC1_ENCODED_BLOCK_SIZE; newData += (blockWidth - 1)*ETC1_ENCODED_BLOCK_SIZE; } // Stick the data back whence it came memcpy(data, am.get(), newDataSz); *width = newWidth; *height = newHeight; return true; }
GLuint loadTextureFromPKM(const ResourcePtr& pkmData, int &width, int &height) { #ifdef GL_ETC1_RGB8_OES const unsigned ETC_PKM_HEADER_SIZE = 16; if (pkmData->data().size() <= ETC_PKM_HEADER_SIZE) { LOGE("pkmData is not the right size. expected > %u, is: %zu", ETC_PKM_HEADER_SIZE, pkmData->data().size()); return TEXTURE_LOAD_ERROR; } etc1_byte* header = &pkmData->data()[0]; if (!etc1_pkm_is_valid(header)) return TEXTURE_LOAD_ERROR; width = etc1_pkm_get_width(header); height = etc1_pkm_get_height(header); size_t encodedDataSize = etc1_get_encoded_data_size(width, height); if (pkmData->data().size() != ETC_PKM_HEADER_SIZE + encodedDataSize) { LOGE("pkmData is not the right size. expected: %zu, is: %zu", ETC_PKM_HEADER_SIZE + encodedDataSize, pkmData->data().size()); return TEXTURE_LOAD_ERROR; } //Now generate the OpenGL texture object GLuint texture = genTexture(); bindTexture2D(texture); compressedTexImage2D(GL_ETC1_RGB8_OES, width, height, encodedDataSize, static_cast<GLvoid*> (&pkmData->data()[ETC_PKM_HEADER_SIZE])); texParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); texParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST); return texture; #else LOGE("PKM texture format not supported by this platform"); return TEXTURE_LOAD_ERROR; #endif }