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.