Problem mit Blending Funktion
-
So sieht meine Blending-Funktion aus:
int MixBlit(HDC destDC, int x, int y, int cx, int cy, HDC srcDC, unsigned char alphaVal) { int i; HBITMAP destBmp; HBITMAP srcBmp; unsigned char* destPixel; unsigned char* srcPixel; BITMAPINFO bi; HDC tdc; HGDIOBJ old; int alpha; if (alphaVal==0) { // Keine Durchsichtigkeit: // srcDC direkt in den destDC kopieren: BitBlt(destDC,x,y,cx,cy,srcDC,0,0,SRCCOPY); return 1; } if (alphaVal==255) { // Volle Durchsichtigkeit - Einfach nicht blitten ;D return 1; } alpha=255-alphaVal; // Für CreateDIBSection() vorbereiten: ZeroMemory(&bi,sizeof(BITMAPINFO)); bi.bmiHeader.biBitCount=24; bi.bmiHeader.biCompression=BI_RGB; bi.bmiHeader.biHeight=cy; bi.bmiHeader.biPlanes=1; bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth=cx; bi.bmiHeader.biSizeImage=cx*cy*3; // MemDC erzeugen: tdc=CreateCompatibleDC(destDC); if (!tdc) { OutputDebugString("CreateCompatibleDC(destDC) failed!\n"); return -1; } // Pixel vom srcDC holen: GdiFlush(); srcBmp=CreateDIBSection(destDC,&bi,DIB_RGB_COLORS,(void**)&srcPixel,NULL,NULL); if (!srcBmp) { OutputDebugString("srcBmp=CreateDIBSection() failed!\n"); return -1; } old=SelectObject(tdc,srcBmp); GdiFlush(); BitBlt(tdc,0,0,cx,cy,srcDC,0,0,SRCCOPY); SelectObject(tdc,old); // Pixel vom destDC holen: GdiFlush(); destBmp=CreateDIBSection(destDC,&bi,DIB_RGB_COLORS,(void**)&destPixel,NULL,NULL); if (!destBmp) { OutputDebugString("destBmp=CreateDIBSection() failed!\n"); return -1; } old=SelectObject(tdc,destBmp); GdiFlush(); BitBlt(tdc,0,0,cx,cy,destDC,x,y,SRCCOPY); SelectObject(tdc,old); GdiFlush(); // Pixel blenden: // Source: http://www.gamedev.net/reference/programming/features/mmxblend/page2.asp for (i=0; i<(cx*cy*3); i++) { destPixel[i] = ( alpha * ( srcPixel[i] - destPixel[i]) ) / 256 + destPixel[i]; } GdiFlush(); // Fertig geblendetes Bild in den destDC blitten: BitBlt(destDC,x,y,cx,cy,tdc,0,0,SRCCOPY); // Aufräumen... DeleteObject(destBmp); DeleteObject(srcBmp); DeleteDC(tdc); return 1; }
Mein Problem sieht man hier: http://www.geeky.de/stuff/prob.gif
Im Original-Bild sieht man ein Rechteck mit dunkelblauem Inhalt und schwarzem Rand, das blitte ich mit meiner MixBlit-Funktion auf eine weisse Fläche. Es sieht auch eigentlich richtig aus, aber eigentlich müsste der Rahmen durchgezogen sein, aber oben ist er nur hin- und wieder mal komplett geschlossen (das soll ne Art Markierung sein - die Rechtecksgröße ändert sich also mal). Da scheine ich irgendwo nen schwerwiegenden Fehler drin zu haben, aber wo ?!
-
Der Fehler liegt in der Schleife:
for (i=0; i<(cx*cy*3); i++) { destPixel = ( alpha * ( srcPixel[i] - destPixel[i]) ) / 256 + destPixel[i]; }
Du schreibst "oben ist er hin- und wieder mal komplett geschlossen". Die Zeilen eines Bitmaps werden immer in vielfachen von 4Byte gespeichert. Also quasi so, wie Structuren auch manchmal ein vielfachen von 4Byte groß sind.
Bei einer Bitmapbreite von 150px sind das150px*3byte/px = 450byte 450 % 4 = true
also werden die Zeilenenden mit 0-Bytes aufgefüllt, bis sich ein vielfaches von 4 ergibt.
Also fehlen am Ende deiner Schleife ein paar Bytes, weil die aligne-Bytes berechnet wurden. Je nach Höhe fehlen halt ziemlich viel.sorry, das ich das so schwer verständlich geschrieben hab, ich hoffe Du verstehst mich :xmas1:
/*
ohh, cool ein Rentier :xmas2:
ohh, und ein Sigma Σ ohh, und ein junges σ
*/// warum kann man Text Fett, [i]kursiv*, unterstrichen, aber nicht durchgestrichen machen?
-
thx, ich lese mir scheinbar dir Remarks im psdk nich richtig durch
(-Hier stand vor dem 'thx!' Schwachsinn-)
-
So sind die Zeilen eines Bitmaps gespeichert:
1.px 2.px 3.px 4.px 2. Zeile |B|G|R |B|G|R |B|G|R |B|G|R 1. Zeile |B|G|R |B|G|R |B|G|R |B|G|R
( 4x2 px )
oder so:
1.px 2.px 3.px 4.px 5.px 2. Zeile |B|G|R |B|G|R |B|G|R |B|G|R |B|G|R |0 1. Zeile |B|G|R |B|G|R |B|G|R |B|G|R |B|G|R |0
( 5x2 px )
Man beachte die Nullen am Ende des 5*2px großen Bitmaps. Damit die Zeilen eben 4*n Byte lang sind.
//Liebes Forum, bitte mach das meine "Grafik" so bleibt, wie ich sie gerade sehe, danke im voraus
-
schön und danke liebes Forum :xmas1:
-
Soweit ich weiß, können nicht alle GDI-Funktionen gebatched werden. Insbesondere nicht die Funktionen, die keinen BOOL zurückgeben. Funktionen, die nicht gebatched werden, flushen automatisch. Demnach sind alle Aufrufe von GdiFlush im oberen Code überflüssig.
Da ich nun kein GDI-Experte bin, stellt sich die Frage, wie es nun wirklich ist. Ohne Grund wird das da wohl kaum stehen. Wär nett, wenn Ihr mich aufklären könntet.
-
Mich hatte da das hier verunsichert:
You need to guarantee that the GDI subsystem has completed any drawing to a bitmap created by CreateDIBSection before you draw to the bitmap yourself. Access to the bitmap must be synchronized. Do this by calling the GdiFlush function. This applies to any use of the pointer to the bitmap bit values, including passing the pointer in calls to functions such as SetDIBits.
...aber da BitBlt() ja normalerweise erst returned wenn es fertig mit zeichnen ist, sind die GdiFlush()-Aufrufe tatsächlich überflüssig...
-
geeky schrieb:
...aber da BitBlt() ja normalerweise erst returned wenn es fertig mit zeichnen ist, sind die GdiFlush()-Aufrufe tatsächlich überflüssig...
Ah, stimmt. Das ist beispielweise eine BOOL-Funktion, die trotzdem nicht gebatched wird. Aber vielen Dank für die Klarstellung. Ich hatte schon daran gedacht, etwas gehörig falsch verstanden zu haben. Nun bin ich wieder beruhigt.
-
...ich frag mich gerade, was mit CreateDIBSection() selber ist.
Vielleicht macht die Funktion ja noch was (z.B. das komplette Bild weiss oder so), nachdem es den HBITMAP-Handle rausgerückt hat...
-
Das GDI ist ein Teil des Kernels und sitzt in win32k.sys. Die Funktionen in gdi32.dll leiten fast alle Aufruf einfach nur weiter (int 0x2E). Das heisst nun aber, daß für jede popelige Zeichenaktion ein Kontext-Switch erforderlich ist. Da jeder Kontext-Switch richtig teuer ist (zeitlich gesehen), wird versucht, eben diese Umschaltungen zu minimieren.
Die Aufrufe werden deswegen nicht sofort bearbeitet, sondern gebündelt. Wird das Bündel zu groß, gibt's nen Flush und mehrere Aufrufe werden gleichzeitig ausgeführt. Die größe des Bündels kannst Du mit GdiGetBatchLimit erfahren und mit GdiSetBatchLimit verändern.
Hast Du eine Funktion, die nicht gebatched werden kann (z.B. BitBlt), wird zunächst ein Flush ausgeführt und die eigentliche Aktion erst danach ausgeführt. Als Ausnahme (wie immer gibt es mindestens eine) zeigt sich hier die Funktion CreateDIBSection. Hier wird vor der Ausführung nichts geflusht, hier mußt Du das selbst erledigen. Solche Ausnamhen sind, wie Du selbst gesehen hast, extra dokumentiert.
Über den Daumen gepeilt kannst Du sagen, daß alle Funktionen die etwas anderes als BOOL zurückgeben, nicht gebatched (lies: nicht in das Bündel geschnürt) werden können (Ausnahmen fallen mir eben nicht ein). Diese Funktionen werden sofort ausgeführt. Es werden hingegen Aufrufe von Funktionen gebatched, die einen BOOL zurückgeben, z.B. MoveToEx, LineTo, Polyline, usw. (Ausnahme: BitBlt, StretchBlt, ...). Solche Funktionen werden unter Umständen erst später ausgführt. Allerspätestens das Freigeben des DCs flusht das Ganze.
Da nun CreateDIBSection keinen BOOL zurückgibt, kannst Du davon ausgehen, daß die Aktion sofort ausgeführt wird. Da passiert nachträglich nichts mehr.
So, hoffentlich habe ich jetzt nicht zuviel altbekanntes erzählt ...