diff --git a/app/src/main/cpp/android-emu.c b/app/src/main/cpp/android-emu.c index 9893f20..05df6e2 100644 --- a/app/src/main/cpp/android-emu.c +++ b/app/src/main/cpp/android-emu.c @@ -96,6 +96,134 @@ VOID CopyItemsToClipboard(HWND hWnd) // save selected Listbox Items to Clipboar return; } +#define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4) + +static BOOL AbsColorCmp(DWORD dwColor1,DWORD dwColor2,DWORD dwTol) +{ + DWORD dwDiff; + + dwDiff = (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); + dwColor1 >>= 8; + dwColor2 >>= 8; + dwDiff += (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); + dwColor1 >>= 8; + dwColor2 >>= 8; + dwDiff += (DWORD) abs((INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF)); + + return dwDiff > dwTol; // FALSE = colors match +} + +static BOOL LabColorCmp(DWORD dwColor1,DWORD dwColor2,DWORD dwTol) +{ + DWORD dwDiff; + INT nDiffCol; + + nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); + dwDiff = (DWORD) (nDiffCol * nDiffCol); + dwColor1 >>= 8; + dwColor2 >>= 8; + nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); + dwDiff += (DWORD) (nDiffCol * nDiffCol); + dwColor1 >>= 8; + dwColor2 >>= 8; + nDiffCol = (INT) (dwColor1 & 0xFF) - (INT) (dwColor2 & 0xFF); + dwDiff += (DWORD) (nDiffCol * nDiffCol); + dwTol *= dwTol; + + return dwDiff > dwTol; // FALSE = colors match +} + +static DWORD EncodeColorBits(DWORD dwColorVal,DWORD dwMask) +{ +#define MAXBIT 32 + UINT uLshift = MAXBIT; + UINT uRshift = 8; + DWORD dwBitMask = dwMask; + + dwColorVal &= 0xFF; // the color component using the lowest 8 bit + + // position of highest bit + while ((dwBitMask & (1<<(MAXBIT-1))) == 0 && uLshift > 0) + { + dwBitMask <<= 1; // next bit + --uLshift; // next position + } + + if (uLshift > 24) // avoid overflow on 32bit mask + { + uLshift -= uRshift; // normalize left shift + uRshift = 0; + } + + return ((dwColorVal << uLshift) >> uRshift) & dwMask; +#undef MAXBIT +} + +extern JavaVM *java_machine; +extern jobject bitmapMainScreen; +extern AndroidBitmapInfo androidBitmapInfo; + +static void MakeBitmapTransparent(HBITMAP hBmp,COLORREF color,DWORD dwTol) { + + BOOL (*fnColorCmp)(DWORD dwColor1,DWORD dwColor2,DWORD dwTol); + if (dwTol >= 1000) { // use CIE L*a*b compare + fnColorCmp = LabColorCmp; + dwTol -= 1000; // remove L*a*b compare selector + } else { // use Abs summation compare + fnColorCmp = AbsColorCmp; + } + + JNIEnv * jniEnv = NULL; + jint ret; + + BOOL needDetach = FALSE; + ret = (*java_machine)->GetEnv(java_machine, (void **) &jniEnv, JNI_VERSION_1_6); + if (ret == JNI_EDETACHED) { + // GetEnv: not attached + ret = (*java_machine)->AttachCurrentThread(java_machine, &jniEnv, NULL); + if (ret == JNI_OK) { + needDetach = TRUE; + } + } + + int destinationWidth = androidBitmapInfo.width; + int destinationHeight = androidBitmapInfo.height; + int destinationBitCount = 32; + int destinationStride = androidBitmapInfo.stride; + void * pixelsDestination = NULL; + if ((ret = AndroidBitmap_lockPixels(jniEnv, bitmapMainScreen, &pixelsDestination)) < 0) { + LOGD("AndroidBitmap_lockPixels() failed ! error=%d", ret); + return; + } + + LPBYTE pbyBits = pixelsDestination; + + // convert COLORREF to RGBQUAD color + DWORD dwRed = 0x00FF0000; + DWORD dwGreen = 0x0000FF00; + DWORD dwBlue = 0x000000FF; + + color = EncodeColorBits((color >> 16), dwBlue) + | EncodeColorBits((color >> 8), dwGreen) + | EncodeColorBits((color >> 0), dwRed); + + DWORD dwBpp = (DWORD) (destinationBitCount >> 3); + LPBYTE pbyColor = pbyBits + (destinationHeight - 1) * destinationStride; + + for (LONG y = 0; y < destinationHeight; ++y) { + LPBYTE pbyLineStart = pbyColor; + for (LONG x = 0; x < destinationWidth; ++x) { + if(!fnColorCmp(*(LPDWORD)pbyColor,color,dwTol)) + *(LPDWORD)pbyColor = 0x00000000; + pbyColor += dwBpp; + } + pbyColor = pbyLineStart - destinationStride; + } + + if(jniEnv && (ret = AndroidBitmap_unlockPixels(jniEnv, bitmapMainScreen)) < 0) + LOGD("AndroidBitmap_unlockPixels() failed ! error=%d", ret); +} + // // WM_PAINT // @@ -127,6 +255,9 @@ static LRESULT OnPaint(HWND hWindow) Paint.rcPaint.right-Paint.rcPaint.left, Paint.rcPaint.bottom-Paint.rcPaint.top, hMainDC, rcMainPaint.left, rcMainPaint.top, SRCCOPY); + if (dwTColor != (DWORD) -1) // prepare background bitmap with transparency + MakeBitmapTransparent((HBITMAP)GetCurrentObject(hPaintDC, OBJ_BITMAP), dwTColor, dwTColorTol); + // CdB for HP: add apples display stuff SetWindowOrgEx(hPaintDC, nBackgroundX, nBackgroundY, NULL); diff --git a/app/src/main/cpp/win32-layer.c b/app/src/main/cpp/win32-layer.c index 0a6f1b6..26d7fb7 100644 --- a/app/src/main/cpp/win32-layer.c +++ b/app/src/main/cpp/win32-layer.c @@ -2026,163 +2026,163 @@ void StretchBltInternal(int xDest, int yDest, int wDest, int hDest, int dst_maxy = yDest + hDest; if(xDest < 0) { - wDest += xDest; - xDest = 0; - } + wDest += xDest; + xDest = 0; + } if(yDest < 0) { - hDest += yDest; - yDest = 0; - } + hDest += yDest; + yDest = 0; + } if(dst_maxx > destinationWidth) - dst_maxx = destinationWidth; + dst_maxx = destinationWidth; if(dst_maxy > destinationHeight) - dst_maxy = destinationHeight; + dst_maxy = destinationHeight; for (int y = yDest; y < dst_maxy; y++) { - int src_cury = ySrc + (y - yDest) * hSrc / hDest; - if(!reverseHeight) - src_cury = sourceHeight - 1 - src_cury; - if (src_cury < 0 || src_cury >= sourceHeight) + int src_cury = ySrc + (y - yDest) * hSrc / hDest; + if(!reverseHeight) + src_cury = sourceHeight - 1 - src_cury; + if (src_cury < 0 || src_cury >= sourceHeight) + continue; + BYTE parity = (BYTE) xSrc; + for (int x = xDest; x < dst_maxx; x++, parity++) { + int src_curx = xSrc + (x - xDest) * wSrc / wDest; + if (src_curx < 0 || src_curx >= sourceWidth) continue; - BYTE parity = (BYTE) xSrc; - for (int x = xDest; x < dst_maxx; x++, parity++) { - int src_curx = xSrc + (x - xDest) * wSrc / wDest; - if (src_curx < 0 || src_curx >= sourceWidth) - continue; - BYTE * sourcePixelBase = pixelsSource + sourceStride * src_cury; - BYTE * destinationPixelBase = pixelsDestination + destinationStride * y; + BYTE * sourcePixelBase = pixelsSource + sourceStride * src_cury; + BYTE * destinationPixelBase = pixelsDestination + destinationStride * y; - COLORREF sourceColor = 0xFF000000; - BYTE * sourceColorPointer = (BYTE *) &sourceColor; + COLORREF sourceColor = 0xFF000000; + BYTE * sourceColorPointer = (BYTE *) &sourceColor; - switch (sourceBitCount) { - case 1: { - //TODO https://devblogs.microsoft.com/oldnewthing/?p=29013 - // When blitting from a monochrome DC to a color DC, - // the color black in the source turns into the destination’s text color, - // and the color white in the source turns into the destination’s background - // color. - BYTE * sourcePixel = sourcePixelBase + ((UINT)src_curx >> (UINT)3); - UINT bitNumber = (UINT) (src_curx % 8); - if(*sourcePixel & ((UINT)1 << bitNumber)) { - // Monochrome 1=White - sourceColorPointer[0] = 255; - sourceColorPointer[1] = 255; - sourceColorPointer[2] = 255; - } else { - // Monochrome 0=Black - sourceColorPointer[0] = 0; - sourceColorPointer[1] = 0; - sourceColorPointer[2] = 0; - } - sourceColorPointer[3] = 255; - break; + switch (sourceBitCount) { + case 1: { + //TODO https://devblogs.microsoft.com/oldnewthing/?p=29013 + // When blitting from a monochrome DC to a color DC, + // the color black in the source turns into the destination’s text color, + // and the color white in the source turns into the destination’s background + // color. + BYTE * sourcePixel = sourcePixelBase + ((UINT)src_curx >> (UINT)3); + UINT bitNumber = (UINT) (src_curx % 8); + if(*sourcePixel & ((UINT)1 << bitNumber)) { + // Monochrome 1=White + sourceColorPointer[0] = 255; + sourceColorPointer[1] = 255; + sourceColorPointer[2] = 255; + } else { + // Monochrome 0=Black + sourceColorPointer[0] = 0; + sourceColorPointer[1] = 0; + sourceColorPointer[2] = 0; } - case 4: { - int currentXBytes = ((sourceBitCount >> (UINT)2) * src_curx) >> (UINT)1; - BYTE * sourcePixel = sourcePixelBase + currentXBytes; - BYTE colorIndex = (parity & (BYTE)0x1 ? sourcePixel[0] & (BYTE)0x0F : sourcePixel[0] >> (UINT)4); - if (palPalEntry) { - sourceColorPointer[0] = palPalEntry[colorIndex].peBlue; - sourceColorPointer[1] = palPalEntry[colorIndex].peGreen; - sourceColorPointer[2] = palPalEntry[colorIndex].peRed; - sourceColorPointer[3] = 255; - } else { - sourceColorPointer[0] = colorIndex; - sourceColorPointer[1] = colorIndex; - sourceColorPointer[2] = colorIndex; - sourceColorPointer[3] = 255; - } - break; - } - case 8: { - BYTE * sourcePixel = sourcePixelBase + src_curx; - BYTE colorIndex = sourcePixel[0]; - if (palPalEntry) { - sourceColorPointer[0] = palPalEntry[colorIndex].peBlue; - sourceColorPointer[1] = palPalEntry[colorIndex].peGreen; - sourceColorPointer[2] = palPalEntry[colorIndex].peRed; - sourceColorPointer[3] = 255; - } else { - sourceColorPointer[0] = colorIndex; - sourceColorPointer[1] = colorIndex; - sourceColorPointer[2] = colorIndex; - sourceColorPointer[3] = 255; - } - break; - } - case 24: { - BYTE * sourcePixel = sourcePixelBase + 3 * src_curx; - sourceColorPointer[0] = sourcePixel[2]; - sourceColorPointer[1] = sourcePixel[1]; - sourceColorPointer[2] = sourcePixel[0]; - sourceColorPointer[3] = 255; - break; - } - case 32: { - BYTE *sourcePixel = sourcePixelBase + 4 * src_curx; - memcpy(sourceColorPointer, sourcePixel, 4); - break; - } - default: - break; + sourceColorPointer[3] = 255; + break; } - - switch (destinationBitCount) { - case 1: { - //TODO https://devblogs.microsoft.com/oldnewthing/?p=29013 - // If you blit from a color DC to a monochrome DC, - // then all pixels in the source that are equal to the background color - // will turn white, and all other pixels will turn black. - // In other words, GDI considers a monochrome bitmap to be - // black pixels on a white background. - BYTE * destinationPixel = destinationPixelBase + (x >> 3); - UINT bitNumber = x % 8; - if(backgroundColor == sourceColor) { - *destinationPixel |= (1 << bitNumber); // 1 White - } else { - *destinationPixel &= ~(1 << bitNumber); // 0 Black - } - break; + case 4: { + int currentXBytes = ((sourceBitCount >> (UINT)2) * src_curx) >> (UINT)1; + BYTE * sourcePixel = sourcePixelBase + currentXBytes; + BYTE colorIndex = (parity & (BYTE)0x1 ? sourcePixel[0] & (BYTE)0x0F : sourcePixel[0] >> (UINT)4); + if (palPalEntry) { + sourceColorPointer[0] = palPalEntry[colorIndex].peBlue; + sourceColorPointer[1] = palPalEntry[colorIndex].peGreen; + sourceColorPointer[2] = palPalEntry[colorIndex].peRed; + sourceColorPointer[3] = 255; + } else { + sourceColorPointer[0] = colorIndex; + sourceColorPointer[1] = colorIndex; + sourceColorPointer[2] = colorIndex; + sourceColorPointer[3] = 255; } - case 4: { - //TODO - break; - } - case 8: { - //TODO - break; - } - case 24: { - BYTE * destinationPixel = destinationPixelBase + 3 * x; - destinationPixel[0] = sourceColorPointer[0]; - destinationPixel[1] = sourceColorPointer[1]; - destinationPixel[2] = sourceColorPointer[2]; - break; - } - case 32: { - BYTE * destinationPixel = destinationPixelBase + 4 * x; - // https://docs.microsoft.com/en-us/windows/desktop/gdi/ternary-raster-operations - // http://www.qnx.com/developers/docs/6.4.1/gf/dev_guide/api/gf_context_set_rop.html - if (rop == ROP_PDSPxax) { // P ^ (D & (S ^ P)) - UINT destination = *((UINT *) destinationPixel); - *((UINT *)destinationPixel) = (brushColor ^ (destination & (sourceColor ^ brushColor))) | 0xFF000000; - } else if (rop == ROP_PSDPxax) { // P ^ (S & (D ^ P)) - UINT destination = *((UINT *) destinationPixel); - *((UINT *)destinationPixel) = (brushColor ^ (sourceColor & (destination ^ brushColor))) | 0xFF000000; - } else if (rop == SRCAND) { // dest = source AND dest - UINT destination = *((UINT *) destinationPixel); - *((UINT *)destinationPixel) = (sourceColor & destination) | 0xFF000000; - } else - *((UINT *)destinationPixel) = sourceColor; - break; - } - default: - break; + break; } + case 8: { + BYTE * sourcePixel = sourcePixelBase + src_curx; + BYTE colorIndex = sourcePixel[0]; + if (palPalEntry) { + sourceColorPointer[0] = palPalEntry[colorIndex].peBlue; + sourceColorPointer[1] = palPalEntry[colorIndex].peGreen; + sourceColorPointer[2] = palPalEntry[colorIndex].peRed; + sourceColorPointer[3] = 255; + } else { + sourceColorPointer[0] = colorIndex; + sourceColorPointer[1] = colorIndex; + sourceColorPointer[2] = colorIndex; + sourceColorPointer[3] = 255; + } + break; + } + case 24: { + BYTE * sourcePixel = sourcePixelBase + 3 * src_curx; + sourceColorPointer[0] = sourcePixel[2]; + sourceColorPointer[1] = sourcePixel[1]; + sourceColorPointer[2] = sourcePixel[0]; + sourceColorPointer[3] = 255; + break; + } + case 32: { + BYTE *sourcePixel = sourcePixelBase + 4 * src_curx; + memcpy(sourceColorPointer, sourcePixel, 4); + break; + } + default: + break; + } + + switch (destinationBitCount) { + case 1: { + //TODO https://devblogs.microsoft.com/oldnewthing/?p=29013 + // If you blit from a color DC to a monochrome DC, + // then all pixels in the source that are equal to the background color + // will turn white, and all other pixels will turn black. + // In other words, GDI considers a monochrome bitmap to be + // black pixels on a white background. + BYTE * destinationPixel = destinationPixelBase + (x >> 3); + UINT bitNumber = x % 8; + if(backgroundColor == sourceColor) { + *destinationPixel |= (1 << bitNumber); // 1 White + } else { + *destinationPixel &= ~(1 << bitNumber); // 0 Black + } + break; + } + case 4: { + //TODO + break; + } + case 8: { + //TODO + break; + } + case 24: { + BYTE * destinationPixel = destinationPixelBase + 3 * x; + destinationPixel[0] = sourceColorPointer[0]; + destinationPixel[1] = sourceColorPointer[1]; + destinationPixel[2] = sourceColorPointer[2]; + break; + } + case 32: { + BYTE * destinationPixel = destinationPixelBase + 4 * x; + // https://docs.microsoft.com/en-us/windows/desktop/gdi/ternary-raster-operations + // http://www.qnx.com/developers/docs/6.4.1/gf/dev_guide/api/gf_context_set_rop.html + if (rop == ROP_PDSPxax) { // P ^ (D & (S ^ P)) + UINT destination = *((UINT *) destinationPixel); + *((UINT *)destinationPixel) = (brushColor ^ (destination & (sourceColor ^ brushColor))) | 0xFF000000; + } else if (rop == ROP_PSDPxax) { // P ^ (S & (D ^ P)) + UINT destination = *((UINT *) destinationPixel); + *((UINT *)destinationPixel) = (brushColor ^ (sourceColor & (destination ^ brushColor))) | 0xFF000000; + } else if (rop == SRCAND) { // dest = source AND dest + UINT destination = *((UINT *) destinationPixel); + *((UINT *)destinationPixel) = (sourceColor & destination) | 0xFF000000; + } else + *((UINT *)destinationPixel) = sourceColor; + break; + } + default: + break; } } + } } UINT SetDIBColorTable(HDC hdc, UINT iStart, UINT cEntries, CONST RGBQUAD *prgbq) { diff --git a/build.gradle b/build.gradle index d47d685..fe28db2 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.1' + classpath 'com.android.tools.build:gradle:3.5.2' // NOTE: Do not place your application dependencies here; they belong