Updates for pre-multiplied alpha (thanks Hugh)

This commit is contained in:
Joshua Granick
2014-02-06 16:31:22 -08:00
parent e351bd6b79
commit 43bc6dfe46
5 changed files with 127 additions and 49 deletions

View File

@@ -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 {

View File

@@ -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()<pfAlpha);
if (use)
surface->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;

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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();