Störungen, in eigener Transparentz Funktion



  • Guckt euch mal diesen Code an, es funktioniert ja halbwegs , aber es kommen Grafikfehler, so einzelne lilane punkte:

    void TransparentBlit(HDC hdc, int destX, int destY, int destWidth, int destHeight, 
                    HDC hdc2, int srcX, int srcY, UINT tranparency)
    {
       unsigned char* pImageBits = NULL;
       unsigned char* pBackBits = NULL;
       BITMAPINFO bmBitmapInfo = {0};
       HBITMAP hBitmap, hBitmap2, hOldBitmap, hOldBitmap2;
       HDC compHDC;
       HDC compHDC2;
    
       // Fill in our BitmapInfo structure (we want a 24 bit image)
       bmBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
       bmBitmapInfo.bmiHeader.biCompression = BI_RGB;
       bmBitmapInfo.bmiHeader.biHeight = destHeight;
       bmBitmapInfo.bmiHeader.biWidth = destWidth;   
       bmBitmapInfo.bmiHeader.biBitCount = 24;
       bmBitmapInfo.bmiHeader.biClrUsed = 0;
       bmBitmapInfo.bmiHeader.biPlanes = 1;
    
       // Create 2 DIB Sections.  One for the Front Buffer and one for the BackBuffer
       hBitmap  = CreateDIBSection(hdc,  &bmBitmapInfo, DIB_RGB_COLORS,(void **)&pImageBits, 0,0);   
       hBitmap2  = CreateDIBSection(hdc,  &bmBitmapInfo, DIB_RGB_COLORS,(void **)&pBackBits, 0,0);
    
       // Create a compatible DC for the front buffer and Select our Dib Section into it
       compHDC = CreateCompatibleDC(hdc);
       hOldBitmap = (HBITMAP)SelectObject(compHDC, hBitmap);
    
       // Create a compatible DC for the back buffer and Select our Dib Section into it
       compHDC2 = CreateCompatibleDC(hdc2);
       hOldBitmap2 = (HBITMAP)SelectObject(compHDC2, hBitmap2);
    
       // Blit the front buffer to our compatible DC that will hold the destination bits
       BitBlt(compHDC, 0, 0, destWidth, destHeight, hdc, destX, destY, SRCCOPY);
    
       // Blit the back buffer to our compatible DC that will hold the source bits
       BitBlt(compHDC2, 0, 0, destWidth, destHeight, hdc2, srcX, srcY, SRCCOPY);
    
       // Loop through the 24 bit image (Times 3 for R G and B)
       for(int i = 0; i < destHeight * destWidth * 3; i += 3)
       {
          // Check if the current pixel being examined isn't the transparent color
          // Remember, the image bits are stored (Blue, Green, Red), not (Red, Green, Blue)
          // We use the system macros to abstract the R G B data
          if((pBackBits[i]   != GetBValue(tranparency)) || 
             (pBackBits[i+1] != GetGValue(tranparency)) || 
             (pBackBits[i+2] != GetRValue(tranparency)))
          {
             // Assign the desired pixel to the foreground
             pImageBits[i]     = pBackBits[i];
             pImageBits[i + 1] = pBackBits[i + 1];
             pImageBits[i + 2] = pBackBits[i + 2];
          }
       }  
    
       // Blit the transparent image to the front buffer (Voila!)
       BitBlt(hdc, destX, destY, destWidth, destHeight, compHDC, 0, 0, SRCCOPY);
    
       // Cleanup the monochrome bitmaps
       SelectObject(compHDC, hOldBitmap);
       SelectObject(compHDC2, hOldBitmap2);   
    
       // Free GDI Resources
       DeleteObject(hBitmap);
       DeleteObject(hBitmap2);
       DeleteDC(compHDC);
       DeleteDC(compHDC2);
    }
    

    [EDIT] Code Tags vergessen [/EDIT]

    [ Dieser Beitrag wurde am 28.01.2003 um 17:36 Uhr von Timm editiert. ]



  • OK, fangen wir ganz oben an. In CreateDIBSection().
    1. Warum allokierst du keinen Speicher für den Buffer ?
    2. Warum nimmst du im Parameter einen VOID** anstatt einen in der MSDN dokumentierten VOID* ?



  • Gut, die erste Frage beantwortet die MSDN:

    [...]the operating system allocates memory for the device-independent bitmap[...]

    Aber die zweite...



  • OK, ich glaub, ich hab was gefunden. Wetten, es geht mit Breiten (destWidth), die durch 4 teilbar sind...



  • Gut. Da du dich so schnell nicht meldest und ich mein Spielchen nicht mit dir spielen kann, sag ich dir, was wahrscheinlich falsch ist. Die Länge einer ScanLine ist DWORD-aligned. Das bedeutet, dass die Länge (in Bytes) einer Zeile in deinem Buffer durch 4 teilbar ist. Sagen wir, die Breite deines Bitmaps beträgt 25 Pixel. Dann hast du 3 * 25 = 75 Bytes in einer ScanLine. Eigentlich. Denn CreateDIBSection() verlängert diese, so dass die Byte-Anzahl durch 4 teilbar ist. Das wären in diesem Beispiel 76. Er haut also noch ein Byte dazu. Das 77-te Byte gehört dann bereits zur nächsten ScanLine.



  • Nicht ganz unrichtig, deine Vermutung ... aber noch lange nicht vollständig! 🙄

    Viel Spass bei deinen weiteren Forschungen! 😉



  • Google mal nach WinGdiEx und klick den ersten Treffer an. Da gibts eine fertige Library dafür. 🕶



  • Auch 'ne Möglichkeit, aber hilft ihm nicht bei seinen Forschungen ... :p

    Ausserdem arbeitet die WinGdiEx aus Geschwindigkeitsgründen intern nicht mit 24-Bit-Bitmaps, sondern ausschließlich mit 32-Bit-Bitmaps, wie sich dem Quellcode entnehmen läßt. 🙄

    Und nebenbei: die in der WinGdiEx enthaltene TransparentBlit-Funktion ist mindestens 20-mal schneller als die hier von Timm wiedergegebene. :o



  • Original erstellt von <JSFreak>:
    Nicht ganz unrichtig, deine Vermutung ... aber noch lange nicht vollständig! 🙄

    Ach ja?? Dann könntest du sie bitte auch vervollständigen!? Das wäre sicher auch in Timms Interesse.



  • Wenn Timm tatsächlich Interesse bekunden sollte, bekommt er eine eMail ... 🕶



  • Warum willst du uns denn nicht allen die Lösung verraten? 🙄



  • Ich weiß es: weil er keinen blassen Schimmer von einer Lösung hat. 😃



  • Sorry, für meinen späten Post, ich hatte noch viel zu tun, Schule und so!!!

    @WebFritzi, so ganz kapier ich das noch nicht... muss ich dann irgendwo +1 hinterschreiben, oder minus nehmen 🙂

    @<...> Der Link ist gut, habs mir schon angeschaut und downloade mir das grad...



  • Ich zeig dir mal wie ich mir das vorstelle:

    DWORD DWORD_ALIGN(DWORD x)
    {
       if(~(~3 | x) != 3)
          x = ((x >> 2) << 2) + 4;
       return x;
    }
    
    void TransparentBlit(HDC hdc, int destX, int destY, int destWidth, int destHeight, 
                    HDC hdc2, int srcX, int srcY, UINT tranparency)
    {
       // ...
    
       // Loop through the 24 bit image (Times 3 for R G and B)
       int diff = DWORD_ALIGN(3 * destWidth) - 3 * destWidth;
       int p = 0;
    
       for(int i = 0; i < destHeight; i++)
       {
          for(int j = 0; j < destWidth; j++) 
          {      
             if((pBackBits[p]   != GetBValue(tranparency)) || 
                (pBackBits[p+1] != GetGValue(tranparency)) || 
                (pBackBits[p+2] != GetRValue(tranparency)))
             {
                // Assign the desired pixel to the foreground
                pImageBits[p]     = pBackBits[p];
                pImageBits[p + 1] = pBackBits[p + 1];
                pImageBits[p + 2] = pBackBits[p + 2];
             }
             p+=3;
          }  
          p+=diff;
       }
    
       // ...
    }
    

    Besonders die DWORD_ALIGN()-Funktion find ich schön. Hab ich selber gemacht. 🙂 Naja, so ungefähr hab ich's mir vorgestellt.

    [ Dieser Beitrag wurde am 31.01.2003 um 03:54 Uhr von WebFritzi editiert. ]



  • Besonders die DWORD_ALIGN()-Funktion find ich schön. Hab ich selber gemacht.

    Herzlichen Glückwunsch. 😉
    Meine Lösung gefällt mir trotzdem besser, ist nicht so kompliziert:
    Ausrichten auf WORD



  • Das ist ein schönes Makro. Obwohl ich's nicht so ganz verstehe. Meine Funktion verstehe ich mittlerweile aber auch nicht mehr. 😉



  • Hab ich mir grad ausgedacht... Würds das nicht auch einfach tun?

    inline DWORD DwordAlign(DWORD x) {
       while((x % 4) > 0)
         ++x;
       return x;
    };
    

    🙂



  • Nö. Ist falsch! Wenn dann so:

    int DWORD_ALIGN(int x)
    {
       int r = x % 4;
       if(r)
          x += r;
       return x;
    }
    

    Verbraucht aber sicher mehr Rechenzeit, denn man arbeitet nicht so nah an der Maschine.


Anmelden zum Antworten