Author Topic: Animation  (Read 7095 times)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: Animation
« Reply #15 on: July 21, 2019, 02:52:19 pm »
This one is to put at the end of Tools.h until there is a better place in mobj.h

Code: [Select]
LONG_PTR zCreateAlphaMask (IN WCHAR* zInputName, IN WCHAR* zInputMask, IN BOOL ReturnBitmap) {
    LONG_PTR nResult = 0;
    LONG_PTR img1 = 0, img2 = 0, graphics1 = 0, graphics2 = 0;
    long imgW1 = 0, imgH1 = 0, imgW2 = 0, imgH2 = 0;
    long S1 = INWSTR(-1, zInputName, (WCHAR*) $DOT);
    if (!FileExist(zInputName)) S1 = 0;
    if (S1) {
        // Make sure that a full path is being used.
        zCheckName(zInputMask);
        long S2 = INWSTR(-1, zInputMask, (WCHAR*) $DOT);
        if (!FileExist(zInputMask)) S2 = 0;
        if (S2 == 0) S1 = 0;
    }
    if (S1) {
        long ImageType = TextureCheckExtension(zInputMask);
        long nRet = -1, nSwapRB = -1;
        if (ImageType == MEDIA_TGA) {
            nRet = ZI_LoadTGA(zInputMask, &img2);
        } else if (ImageType == MEDIA_DDS) {
            nRet = ZI_LoadDDS(zInputMask, &img2, &nSwapRB);
        } else { // all GDI+
            nRet = GdipLoadImageFromFile(zInputMask, img2);
        }
        if (nRet == 0) {
            GetImageSize(img2, imgW2, imgH2);
            nRet = -1, nSwapRB = -1;
            ImageType = TextureCheckExtension(zInputName);
            if (ImageType == MEDIA_TGA) {
                nRet = ZI_LoadTGA(zInputName, &img1);
            } else if (ImageType == MEDIA_DDS) {
                nRet = ZI_LoadDDS(zInputName, &img1, &nSwapRB);
            } else { // all GDI+
                nRet = GdipLoadImageFromFile(zInputName, img1);
            }
            if (nRet == 0) {
                GetImageSize(img1, imgW1, imgH1);
                if ((imgW1 == imgW2) && (imgH1 == imgH2)) {
                    HDC hDC = zDisplayDC();
                    HDC ImgHDC = CreateCompatibleDC(hDC);
                    HBITMAP hbmReturn = zCreateDIBSection(hDC, imgW1, imgH1, 32);
                    SelectObject(ImgHDC, hbmReturn);

                    HDC MaskHDC = CreateCompatibleDC(hDC);
                    HBITMAP hbmMask = zCreateDIBSection(hDC, imgW2, imgH2, 32);
                    SelectObject(MaskHDC, hbmMask);
                    DeleteDC(hDC);

                    if (GdipCreateFromHDC(MaskHDC, graphics2) == 0) {
                        if (GdipDrawImageRectI(graphics2, img2, 0, 0, imgW2, imgH2) == 0) {
                            // Draw image
                            if (GdipCreateFromHDC(ImgHDC, graphics1) == 0) {
                                if (GdipDrawImageRectI(graphics1, img1, 0, 0, imgW1, imgH1) == 0) {
                                    long AlphaRGB1 = 0, AlphaRGB2 = 0;
                                    GdipBitmapGetPixel(img2, 0, 0, AlphaRGB2);
                                    BITMAP bm2 = { 0 };
                                    GetObject(hbmMask, sizeof(bm2), &bm2);
                                    BYTE* pBits2 = (BYTE*) bm2.bmBits;

                                    GdipBitmapGetPixel(img1, 0, 0, AlphaRGB1);
                                    BITMAP bm1 = { 0 };
                                    GetObject(hbmReturn, sizeof(bm1), &bm1);
                                    BYTE* pBits1 = (BYTE*) bm1.bmBits;
                                    for (long y = 0; y < bm1.bmHeight; ++y) {
                                        for (long x = 0; x < bm1.bmWidth; ++x) {
                                            pBits1[3] = (BYTE) ((pBits2[2] * 0.2989f) + (pBits2[1] * 0.5870f) + (pBits2[0] * 0.114f));
                                            pBits2 += 4;
                                            pBits1 += 4;
                                        }
                                    }
                                }
                                // Cleanup
                                GdipDeleteGraphics(graphics1);
                            }
                            if (img1) { GdipDisposeImage(img1); img1 = 0; }
                            img1 = zBitmapToImage(ImgHDC);
                            if (ImgHDC) DeleteDC(ImgHDC);
                            DeleteObject(hbmReturn);
                        }

                        if (img2) { GdipDisposeImage(img2); img2 = 0; }
                        if (graphics2) GdipDeleteGraphics(graphics2);
                    }
                    if (MaskHDC) DeleteDC(MaskHDC);
                    DeleteObject(hbmMask);
                }
            }
        }
    }

    if (img1) {
        HDC hDC = zDisplayDC();
        HDC ImgHDC = CreateCompatibleDC(hDC);
        HBITMAP hbmReturn = zCreateDIBSection(hDC, imgW1, imgH1, 32);
        SelectObject(ImgHDC, hbmReturn);
        DeleteDC(hDC);
        // Draw image
        if (GdipCreateFromHDC(ImgHDC, graphics1) == 0) {
            for (long K = 0; K < 4; K++) { // Increase opacity
                GdipDrawImageRectI(graphics1, img1, 0, 0, imgW1, imgH1);
            }
            // Cleanup
            GdipDeleteGraphics(graphics1);
        }
        GdipDisposeImage(img1);
        if (ReturnBitmap) {
            DeleteDC(ImgHDC);
            nResult = (LONG_PTR) hbmReturn;
        } else {
            nResult = zBitmapToImage(ImgHDC);
            DeleteDC(ImgHDC);
            DeleteObject(hbmReturn);
        }
    }
    return nResult;
}

and the missing GdipDrawImageRectI API to add into Tools.h after GdipDeleteGraphics.

Code: [Select]
long GdipDrawImageRectI(IN LONG_PTR graphics, IN LONG_PTR lpImg, IN long x, IN long y, IN long W, IN long H) {
    long nRet = -1; // Error
    HMODULE hModule = gdiplib();
    if (hModule) {
        long_proc (LONG_PTR, LONG_PTR, long, long, long, long);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc) GetProcAddress(hModule, "GdipDrawImageRectI"); }
        if (hProc) { nRet = hProc(graphics, lpImg, x, y, W, H); }
    }
    return nRet;
}

Warning, the zCreateAlphaMask code has not been tested yet.

The function returns either a gdiplus LONG_PTR or a HBITMAP handle if ReturnBitmap is TRUE.

It is up to you to cleanup the bitmap handle or the gdiplus LONG_PTR once done.

Look at the "Increase opacity" loop, 4 seems the good value to me, this is what i am using in my standalone utility.

Quote
why wouldn't you also add alpha mask GDI+ AA resizing to fit the diffuse texture size if necessary?
I do not understand what you mean.
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animation
« Reply #16 on: July 21, 2019, 06:19:46 pm »
I do not understand what you mean.

You said:

However the size of the two files must match.

As I understood it, you were trying to say that the resolution (i.e. image physical size, or width in pxs * height in pxs) of the color and alpha maps to merge should be the same, say, 1024 * 1024 pxs both.

So, my question was why couldn't we just resize (using GDI+ high-quality anti-aliasing) the alpha mask size to match the color map size in case they happen to be different?
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: Animation
« Reply #17 on: July 22, 2019, 09:55:04 am »
Ok, the standalone version has been checked successfully.

Here is the source (source.zip) and the binary EXE with a couple of images for test purpose.

Test it in command line mode, like this:

alphamask hair.jpg larger_mask.jpg

The mask is resized on the fly to match the size of the zInputName.

The resulting alpha_InputName is saved as a .png file.

You should be able to use directly the zCreateAlphaMask inside of OR.
« Last Edit: July 22, 2019, 10:31:11 am by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Michael Lobko-Lobanovsky

  • Administrator
  • *****
  • Posts: 1481
Re: Animation
« Reply #18 on: July 22, 2019, 01:46:04 pm »
Thank you, Patrice!

I'll get in touch with you when tested.
Mike
(3.6GHz Intel Core i5 Quad w/ 16GB RAM, nVidia GTX 1060Ti w/ 6GB VRAM, Windows 7 Ultimate Sp1)