/* * ETC Texture Compressor * 2013-03-20 * M. Kim */ #include #include #include #include #include #include #include #include "rg_etc1.h" #define LOG_TAG "unity plugin" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { LOGI("after %s() glError (0x%x)\n", op, error); } } int g_etcInited = 0; struct compressor_t { GLuint glTex; int w; int h; int count; void** in; unsigned int* out; }; extern "C" void* GenTextureCompressor(void* texPtr, int w, int h, int mipmapCount, void* mipmapData[]) { if (!g_etcInited) { rg_etc1::pack_etc1_block_init(); g_etcInited = 1; } compressor_t* compressor = new compressor_t; compressor->glTex = (GLuint)(size_t)(texPtr); compressor->w = w; compressor->h = h; compressor->count = mipmapCount; compressor->in = new void*[mipmapCount]; for (int i = 0; i < mipmapCount; i++) compressor->in[i] = mipmapData[i]; compressor->out = NULL; return compressor; } extern "C" void CompressTexture(compressor_t* compressor) { int w = compressor->w; int h = compressor->h; int memSize = 0; for (int i = 0; i < compressor->count; i++) { if (w == 0) w = 1; if (h == 0) h = 1; int dataSize = (w * h) >> 1; // bytes if (dataSize < 8) dataSize = 8; memSize += dataSize; //LOGI("%d x %d: %d", w, h, dataSize); w >>= 1; h >>= 1; } compressor->out = new unsigned int[memSize >> 2]; w = compressor->w; h = compressor->h; unsigned int* compressed = compressor->out; rg_etc1::etc1_pack_params params; params.m_quality = rg_etc1::cLowQuality; params.m_dithering = false; for (int i = 0; i < compressor->count ; i++) { if (w == 0) w = 1; if (h == 0) h = 1; unsigned int* data = (unsigned int*)compressor->in[i]; if (w >= 4 && h >= 4) { for (int y = 0; y < h / 4; y++) { for (int x = 0; x < w / 4; x++) { unsigned int src_blk[16]; unsigned int* d = src_blk; unsigned int* s = &data[y * 4 * w + x * 4]; for (int k = 0; k < 4; k++) { *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; s += w - 4; //if (x == 0 && y == 0) // LOGI("%08x %08x %08x %08x", *(d - 3), *(d - 2), *(d - 1), *d); } rg_etc1::pack_etc1_block(compressed, src_blk, params); compressed += 2; } } //LOGI("[%d] %d x %d [%08xh]: ok", i, w, h, data); } else { //LOGI("[%d] %d x %d [%08xh]", i, w, h, data); unsigned int p[16]; for (int j = 0; j < 16; j++) { p[j] = data[j % (w * h)]; } rg_etc1::pack_etc1_block(compressed, p, params); compressed += 2; } w >>= 1; h >>= 1; } } extern "C" void UploadCompressedTexture(compressor_t* compressor) { glBindTexture(GL_TEXTURE_2D, compressor->glTex); checkGlError("glBindTexture"); int w = compressor->w; int h = compressor->h; unsigned char* data = (unsigned char*)compressor->out; for (int i = 0; i < compressor->count; i++) { if (w == 0) w = 1; if (h == 0) h = 1; int dataSize = (w * h) >> 1; // bytes if (dataSize < 8) dataSize = 8; glCompressedTexImage2D(GL_TEXTURE_2D, i, GL_ETC1_RGB8_OES, w, h, 0, dataSize, data); checkGlError("glCompressedTexImage2D"); data += dataSize; w >>= 1; h >>= 1; } delete[] compressor->out; delete[] compressor->in; delete compressor; } extern "C" void UploadCompressedTexImage2D( void* texPtr, GLuint glLevel, GLuint glInternalformat, GLuint width, GLuint height, GLuint border, GLuint imageSize, void* imgdata) { GLuint glNativeTextureID = (GLuint)(size_t)(texPtr); glBindTexture(GL_TEXTURE_2D, glNativeTextureID); checkGlError("glBindTexture"); glCompressedTexImage2D( GL_TEXTURE_2D, 0, GL_ETC1_RGB8_OES, width, height, 0, imageSize, imgdata); checkGlError("glCompressedTexImage2D"); LOGI(">>> [%d] <<< (%d x %d) len=%d : ok", glNativeTextureID, width, height, imageSize); }