2016-05-17 17 views
0

Ich muss Teile einer Bitmap (nicht rechteckig) mit Direct2D wie Bilder unten zeichnen. Es ist so, als ob der Benutzer in Photoshop eine neue Ebene basierend auf der ausgewählten Region (HRGN) erstellen und verschieben kann. Das nächste Beispiel, das ich finden konnte, war here, aber ich konnte es nicht funktionieren lassen. Weiß jemand, wie man das macht?Zeichnen und Erstellen keine rechteckigen Bitmaps mit Direct2d

Danke

enter image description hereenter image description here

bearbeiten

Es sieht aus wie Menschen falsch verstanden haben, was ich erreichen wollte. Dieses neue animierte GIF sollte es besser erklären.

enter image description here

+0

Muss es AntiAliased sein? – kizeloo

+0

Es wäre schön, wenn das möglich wäre, wenn nicht, ich würde mich freuen, es einfach ohne Anti-Aliasing anzuzeigen. – Sam

+0

Wie wird es in Ihrem Fenster angezeigt? – kizeloo

Antwort

1

Nachdem ich mich wie eine Million versucht und versagt fühlte, fand ich die Antwort. Microsofts Anweisungen zum Erstellen einer Bitmap-Deckkraftmaske in here und here sind sehr verwirrend und es klingt, als ob Sie ein Schwarz-Weiß-Bild als Maske benötigen, aber das ist weit von der Wahrheit entfernt. Was wir wirklich brauchen, ist ein Bild, das nur Alpha-Wert Informationen hat. Auch konnte ich keine Anweisung zum Umwandeln einer HRGN in eine ID2D1Bitmap finden. Also musste ich mir meine eigene ausdenken, die ich hier für jeden teilen werde, der das gleiche Problem haben könnte.

void HRGN_to_D2Bitmap(const DWORD bmpWidth, const DWORD bmpHeight, HRGN hShape, ID2D1RenderTarget* pRT, ID2D1Bitmap** ppBmpMask) 
{ 
    boost::scoped_ptr<unsigned char> pBmpBuff(new unsigned char[bmpWidth * bmpHeight]); 
    DWORD dwCount; 
    LPRGNDATA pRgnData; 

    memset(pBmpBuff.get(), 0, bmpWidth * bmpHeight); 
    dwCount = ::GetRegionData(hShape, 0, NULL); 
    boost::scoped_ptr<unsigned char> pRgnBuff(new unsigned char[dwCount]); 
    pRgnData = reinterpret_cast<LPRGNDATA>(pRgnBuff.get()); 
    if (dwCount == ::GetRegionData(hShape, dwCount, pRgnData)) 
    { 
     DWORD i, y; 
     RECT* pRect; 
     D2D1_BITMAP_PROPERTIES bmpPorp; 
     D2D1_SIZE_U bmpSize = D2D1::SizeU(bmpWidth, bmpHeight); 

     pRect = (RECT*)pRgnData->Buffer; 
     for (i = 0; i < pRgnData->rdh.nCount; i++) 
     { 
      for (y = (DWORD)pRect->top; ((y < (DWORD)pRect->bottom) && (y < bmpHeight)); y++) 
       memset(&pBmpBuff.get()[(y * bmpWidth) + pRect->left], 0xFFFFFFFF, pRect->right - pRect->left); 
      pRect++; 
     } 
     bmpPorp.dpiX = 0.0f; 
     bmpPorp.dpiY = 0.0f; 
     bmpPorp.pixelFormat.format = DXGI_FORMAT_A8_UNORM; 
     bmpPorp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_STRAIGHT; 
     pRT->CreateBitmap(bmpSize, pBmpBuff.get(), bmpWidth, bmpPorp, ppBmpMask); 
    } 
} 

Ich habe die meisten der Fehlerprüfung aus Gründen der Einfachheit weggelassen.
Wenn die Funktion zurückkehrt, sollte der letzte Parameter eine gültige Bitmap-Maske haben (wenn alles korrekt funktioniert hat), die von FillOpacityMask Funktion von ID2D1RenderTarget verwendet werden soll.
Jetzt müssen wir unsere ID2D1Bitmap in eine ID2D1BitmapBrush drehen.

D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = D2D1::BitmapBrushProperties(
        D2D1_EXTEND_MODE_CLAMP, 
        D2D1_EXTEND_MODE_CLAMP, 
        D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR 
        ); 

pRT->CreateBitmapBrush(pOrigBmp, propertiesXClampYClamp, &bkBrush); 

pOrigBmp ist das Bild, das wir um und bkBrush ist ein Zeiger auf ID2D1BitmapBrush verschieben möchten.
Wenn Sie einen HBITMAP oder bei C++ Builder Jungs ein TBitmap, können Sie den Befehl zum Umwandeln einer Bitmap ID2D1Bitmaphere finden.
Jetzt jedes Mal wollen Sie Ihre Fenster malen, können Sie einfach tun:

pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); 
pRT->FillOpacityMask(pBmpMask, bkBrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS); 
pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); 

Für das Bild bewegen wir SetTransform verwenden.pBmpMask ist eine ID2D1Bitmap, die mit HRGN_to_D2Bitmap erstellt wurde. ie:

ID2D1Bitmap* pBmpMask; 

HRGN_to_D2Bitmap(bmpWidth, bmpHeight, hShape, pRT, &pBmpMask); 

Ich hoffe, dies ist hilfreich.
Sam

0

Ok, ich habe es. Soll ich Ihnen die Projektquelle per E-Mail schicken? Es ist C++ Builder 6, also sollte Ihre Version es konvertieren können. Ich hatte Recht, dass FullRepaint für das TPanel auf false gesetzt werden musste.

Die Grundidee besteht darin, ein TImage auf ein TPanel zu setzen und dann das hRGN des Panels basierend auf der transparenten Farbe des Bildes, das Sie verwenden möchten, auszuschneiden. Stellen Sie außerdem sicher, dass die "FullRepaint" -Eigenschaft des TPanel auf "false" gesetzt ist, sonst erhalten Sie das Flimmern, das Sie notiert haben. So habe ich die Bewegungsanimation für ein Paar Spiele gemacht, die ich gemacht habe.

+0

Auch habe ich Ihre PNGs in BMPs – kizeloo

+0

Ich könnte auch Anweisungen, aber E-Mail-Versand wäre wahrscheinlich einfacher für Sie. – kizeloo

+0

Danke für die Mühe. Ich schätze es sehr. Ich habe den ursprünglichen Beitrag geändert, um das Problem besser zu erklären. Ich habe bereits eine funktionierende Version, die GDI (TImage) verwendet, aber die Bilder, mit denen ich arbeite, sind wirklich groß und machen es in GDI schafft ein Flimmerproblem. Ich hatte gehofft, es auf Direct2D zu verbessern, um die Bewegung des beweglichen Teils glatter und flimmerfrei zu machen. Nochmals vielen Dank für Ihre Bemühungen. Übrigens hat Stackoverflow kein privates Nachrichtensystem und das Versenden der E-Mail-Adresse verlangt nur Ärger. – Sam

Verwandte Themen