From 43bc6dfe4665fc3722320a8d45d9e78881125519 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 6 Feb 2014 16:31:22 -0800 Subject: [PATCH] Updates for pre-multiplied alpha (thanks Hugh) --- project/include/renderer/common/Surface.h | 9 ++- project/src/common/ExternalInterface.cpp | 24 ++++++ project/src/renderer/common/SimpleSurface.cpp | 7 ++ project/src/renderer/opengl/OpenGLContext.cpp | 57 +++++++------ project/src/renderer/opengl/OpenGLTexture.cpp | 79 +++++++++++++------ 5 files changed, 127 insertions(+), 49 deletions(-) diff --git a/project/include/renderer/common/Surface.h b/project/include/renderer/common/Surface.h index 126d59a1c..00dd9e23b 100644 --- a/project/include/renderer/common/Surface.h +++ b/project/include/renderer/common/Surface.h @@ -14,7 +14,14 @@ namespace lime { void HintColourOrder (bool inRedFirst); - enum { SURF_FLAGS_NOT_REPEAT_IF_NON_PO2 = 0x0001 }; + + enum { + + SURF_FLAGS_NOT_REPEAT_IF_NON_PO2 = 0x0001, + SURF_FLAGS_USE_PREMULTIPLIED_ALPHA = 0x0002, + SURF_FLAGS_HAS_PREMULTIPLIED_ALPHA = 0x0004 + + }; class Surface : public Object { diff --git a/project/src/common/ExternalInterface.cpp b/project/src/common/ExternalInterface.cpp index 87fbe1c2a..76f5ae18a 100644 --- a/project/src/common/ExternalInterface.cpp +++ b/project/src/common/ExternalInterface.cpp @@ -3036,6 +3036,30 @@ value lime_bitmap_data_height(value inHandle) } DEFINE_PRIM(lime_bitmap_data_height,1); +value lime_bitmap_data_get_prem_alpha(value inHandle) +{ + Surface *surface; + if (AbstractToObject(inHandle,surface)) + return alloc_bool(surface->GetFlags() & SURF_FLAGS_USE_PREMULTIPLIED_ALPHA); + return alloc_null(); +} +DEFINE_PRIM(lime_bitmap_data_get_prem_alpha,1); + +value lime_bitmap_data_set_prem_alpha(value inHandle,value inVal) +{ + Surface *surface; + if (AbstractToObject(inHandle,surface)) + { + bool use = val_bool(inVal) && (surface->Format()SetFlags( surface->GetFlags() | SURF_FLAGS_USE_PREMULTIPLIED_ALPHA ); + else + surface->SetFlags( surface->GetFlags() & ~SURF_FLAGS_USE_PREMULTIPLIED_ALPHA ); + } + return alloc_null(); +} +DEFINE_PRIM(lime_bitmap_data_set_prem_alpha,2); + value lime_bitmap_data_clear(value inHandle,value inRGB) { Surface *surface; diff --git a/project/src/renderer/common/SimpleSurface.cpp b/project/src/renderer/common/SimpleSurface.cpp index c8a94748a..89272110e 100644 --- a/project/src/renderer/common/SimpleSurface.cpp +++ b/project/src/renderer/common/SimpleSurface.cpp @@ -652,6 +652,9 @@ namespace lime { if (!mBase) return; + if (mFlags & SURF_FLAGS_HAS_PREMULTIPLIED_ALPHA) + return; + Rect r = Rect (0, 0, mWidth, mHeight); mVersion++; if (mTexture) @@ -683,6 +686,8 @@ namespace lime { } + mFlags |= SURF_FLAGS_HAS_PREMULTIPLIED_ALPHA; + } @@ -1037,6 +1042,8 @@ namespace lime { } + mFlags &= ~SURF_FLAGS_HAS_PREMULTIPLIED_ALPHA; + } diff --git a/project/src/renderer/opengl/OpenGLContext.cpp b/project/src/renderer/opengl/OpenGLContext.cpp index d596df2e9..f620585d7 100644 --- a/project/src/renderer/opengl/OpenGLContext.cpp +++ b/project/src/renderer/opengl/OpenGLContext.cpp @@ -390,35 +390,19 @@ namespace lime { } - switch (element.mBlendMode) { - - case bmAdd: - - glBlendFunc (GL_SRC_ALPHA, GL_ONE); - break; - - case bmMultiply: - - glBlendFunc (GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); - break; - - case bmScreen: - - glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_COLOR); - break; - - default: - - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - - } - int progId = 0; + bool premAlpha = false; if ((element.mFlags & DRAW_HAS_TEX) && element.mSurface) { + if (element.mSurface->GetFlags () & SURF_FLAGS_USE_PREMULTIPLIED_ALPHA) { + + premAlpha = true; + + } + progId |= PROG_TEXTURE; + if (element.mSurface->BytesPP () == 1) { progId |= PROG_ALPHA_TEXTURE; @@ -473,6 +457,31 @@ namespace lime { } + + switch (element.mBlendMode) { + + case bmAdd: + + glBlendFunc (GL_SRC_ALPHA, GL_ONE); + break; + + case bmMultiply: + + glBlendFunc (GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + break; + + case bmScreen: + + glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_COLOR); + break; + + default: + + glBlendFunc (premAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + + } + if (prog != lastProg) { if (lastProg) { diff --git a/project/src/renderer/opengl/OpenGLTexture.cpp b/project/src/renderer/opengl/OpenGLTexture.cpp index fd3ed8f2d..a2879a308 100644 --- a/project/src/renderer/opengl/OpenGLTexture.cpp +++ b/project/src/renderer/opengl/OpenGLTexture.cpp @@ -4,6 +4,8 @@ namespace lime { + static int *sAlpha16Table = 0; + bool gFullNPO2Support = false; bool gPartialNPO2Support = false; @@ -68,6 +70,25 @@ namespace lime { } + int *getAlpha16Table () { + + if (sAlpha16Table == 0) { + + sAlpha16Table = new int[256]; + + for (int a = 0; a < 256; a++) { + + sAlpha16Table[a] = a * (1 << 16) / 255; + + } + + } + + return sAlpha16Table; + + } + + OpenGLTexture::OpenGLTexture (Surface *inSurface, unsigned int inFlags) { mPixelWidth = inSurface->Width (); @@ -75,7 +96,7 @@ namespace lime { mDirtyRect = Rect (0, 0); mContextVersion = gTextureContextVersion; - bool non_po2 = NonPO2Supported (true && (inFlags & SURF_FLAGS_NOT_REPEAT_IF_NON_PO2)); + bool non_po2 = NonPO2Supported (inFlags & SURF_FLAGS_NOT_REPEAT_IF_NON_PO2); //printf("Using non-power-of-2 texture %d\n",non_po2); int w = non_po2 ? mPixelWidth : UpToPower2 (mPixelWidth); @@ -86,7 +107,11 @@ namespace lime { mTextureWidth = w; mTextureHeight = h; - bool copy_required = inSurface->GetBase () && (w != mPixelWidth || h != mPixelHeight); + bool usePreAlpha = inFlags & SURF_FLAGS_USE_PREMULTIPLIED_ALPHA; + bool hasPreAlpha = inFlags & SURF_FLAGS_HAS_PREMULTIPLIED_ALPHA; + int *multiplyAlpha = usePreAlpha && !hasPreAlpha ? getAlpha16Table () : 0; + + bool copy_required = inSurface->GetBase () && (w != mPixelWidth || h != mPixelHeight || multiplyAlpha); Surface *load = inSurface; @@ -96,10 +121,6 @@ namespace lime { int pixels = GL_UNSIGNED_BYTE; int gpuFormat = inSurface->GPUFormat (); - //if (inSurface) { - //inSurface->multiplyAlpha(); - //} - if (!inSurface->GetBase ()) { if (gpuFormat != fmt) @@ -125,20 +146,44 @@ namespace lime { for (int y = 0; y < mPixelHeight; y++) RGBX_to_RGB565 (buffer + y * mTextureWidth * 2, inSurface->Row (y), mPixelWidth); - } else if (w != mPixelWidth || h != mPixelHeight) { + } else if (copy_required) { int pw = (inSurface->Format () == pfAlpha ? 1 : 4); buffer = (uint8 *)malloc (pw * mTextureWidth * mTextureHeight); + for (int y = 0; y < mPixelHeight; y++) { const uint8 *src = inSurface->Row (y); uint8 *b = buffer + (mTextureWidth * pw * y); - memcpy (b, src, mPixelWidth * pw); + + if (multiplyAlpha) { + + for (int x = 0; x < mPixelWidth; x++) { + + int a16 = multiplyAlpha[src[3]]; + b[0] = (src[0] * a16) >> 16; + b[1] = (src[1] * a16) >> 16; + b[2] = (src[2] * a16) >> 16; + b[3] = src[3]; + b += 4; + src += 4; + + } + + } else { + + memcpy (b, src, mPixelWidth * pw); + b += mPixelWidth * pw; + + } + + // Duplicate last pixel to help with bilinear interpolation if (w > mPixelWidth) - memcpy (b + (mPixelWidth * pw), buffer + (mPixelWidth - 1) * pw, pw); + memcpy (b, buffer + ((mPixelWidth - 1) * pw), pw); } + // Duplicate last Row to help with bilinear interpolation if (h != mPixelHeight) { uint8 *b = buffer + (mTextureWidth * pw * mPixelHeight); @@ -153,20 +198,6 @@ namespace lime { } - /*#ifdef LIME_PREMULTIPLIED_ALPHA - if (store_format != GL_ALPHA) { - - for (int i = 0; i < mTextureWidth * mTextureHeight * 4; i += 4) { - - float a = buffer[i + 3] / 255.0; - buffer[i] = int(buffer[i] * a); - buffer[i + 1] = int(buffer[i + 1] * a); - buffer[i + 2] = int(buffer[i + 2] * a); - - } - - } - #endif*/ glGenTextures (1, &mTextureID); // __android_log_print(ANDROID_LOG_ERROR, "lime", "CreateTexture %d (%dx%d)", @@ -195,7 +226,7 @@ namespace lime { #endif #ifndef LIME_FORCE_GLES2 - glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + //glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #endif //int err = glGetError();