Panoramica dei pennelli
Questa panoramica descrive come creare e usare ID2D1SolidColorBrush, ID2D1LinearGradientBrush, ID2D1RadialGradientBrushe OGGETTI ID2D1BitmapBrush per disegnare aree con colori a tinta unita, sfumature e bitmap. Contiene le sezioni seguenti.
Prerequisiti
Questa panoramica presuppone che si abbia familiarità con la struttura di un'applicazione Direct2D di base, come descritto in Creare una semplice applicazione Direct2D.
Tipi di pennello
Un pennello "dipinge" un'area con il suo output. I pennelli diversi hanno tipi diversi di output. Direct2D fornisce quattro tipi di pennello: ID2D1SolidColorBrush disegna un'area con un colore a tinta unita, ID2D1LinearGradientBrush con una sfumatura lineare, ID2D1RadialGradientBrush con una sfumatura radiale e ID2D1BitmapBrush con una bitmap.
Nota
A partire da Windows 8, puoi anche usare ID2D1ImageBrush, simile a un pennello bitmap, ma puoi usare anche primitive.
Tutti i pennelli ereditano da ID2D1Brush e condividono un set di funzionalità comuni (impostazione e recupero dell'opacità e trasformazione dei pennelli); vengono creati da ID2D1RenderTarget e sono risorse dipendenti dal dispositivo: l'applicazione deve creare pennelli dopo aver inizializzato la destinazione di rendering con cui verranno usati i pennelli e ricreare i pennelli ogni volta che la destinazione di rendering deve essere ricreata. Per altre informazioni sulle risorse, vedere Panoramica delle risorse .
La figura seguente mostra esempi di ognuno dei diversi tipi di pennello.
Nozioni di base sul colore
Prima di disegnare con un ID2D1SolidColorBrush o un pennello sfumato, è necessario scegliere i colori. In Direct2D i colori sono rappresentati dalla struttura D2D1_COLOR_F (che in realtà è solo un nuovo nome per la struttura usata da Direct3D, D3DCOLORVALUE).
Prima di Windows 8, D2D1_COLOR_F usa la codifica sRGB. La codifica sRGB divide i colori in quattro componenti: rosso, verde, blu e alfa. Ogni componente è rappresentato da un valore a virgola mobile con un intervallo normale compreso tra 0,0 e 1,0. Il valore 0,0 indica l'assenza completa di tale colore, mentre il valore 1,0 indica che il colore è completamente presente. Per il componente alfa, 0,0 rappresenta un colore completamente trasparente e 1.0 rappresenta un colore completamente opaco.
A partire da Windows 8, D2D1_COLOR_F accetta anche la codifica scRGB. scRGB è un superset di che consente valori di colore superiori a 1,0 e inferiori a 0,0.
Per definire un colore, è possibile utilizzare la struttura D2D1_COLOR_F e inizializzare manualmente i relativi campi oppure usare la classe D2D1::ColorF per creare il colore. La classe ColorF fornisce diversi costruttori per la definizione dei colori. Se il valore alfa non viene specificato nei costruttori, per impostazione predefinita è 1.0.
Utilizzare il costruttore ColorF(Enum, FLOAT) per specificare un colore predefinito e un valore del canale alfa. Un valore del canale alfa è compreso tra 0,0 e 1,0, dove 0,0 rappresenta un colore completamente trasparente e 1,0 rappresenta un colore completamente opaco. La figura seguente mostra diversi colori predefiniti e i relativi equivalenti esadecimali. Per un elenco completo dei colori predefiniti, vedere la sezione Costanti Color della classeColorF.
L'esempio seguente crea un colore predefinito e lo usa per specificare il colore di un ID2D1SolidColorBrush.
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
&m_pBlackBrush
);
Utilizzare il costruttore ColorF(FLOAT, FLOAT, FLOAT, FLOAT) per specificare un colore nella sequenza di rosso, verde, blu ed alfa, dove ciascun elemento ha un valore compreso tra 0,0 e 1,0.
Nell'esempio seguente vengono specificati i valori rosso, verde, blu e alfa per un colore.
ID2D1SolidColorBrush *pGridBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
&pGridBrush
);
- Usare il costruttore ColorF(UINT32, FLOAT) per specificare il valore esadecimale di un colore e un valore alfa, come mostrato nell'esempio seguente.
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),
&m_pYellowGreenBrush
);
Modalità alfa
Indipendentemente dalla modalità alfa della destinazione di rendering con cui si usa un pennello, i valori D2D1_COLOR_F vengono sempre interpretati come alfa dritti.
Uso di pennelli a tinta unita
Per creare un pennello a tinta unita, chiamare il metodo ID2D1RenderTarget::CreateSolidColorBrush, che restituisce un valore HRESULT e un oggetto ID2D1SolidColorBrush. La figura seguente mostra un quadrato disegnato con un pennello di colore nero e disegnato con un pennello a tinta unita con il valore di colore 0x9ACD32.
Il codice seguente illustra come creare e usare un pennello colore nero e un pennello con un valore di colore 0x9ACD32 per riempire e disegnare questo quadrato.
ID2D1SolidColorBrush *m_pBlackBrush;
ID2D1SolidColorBrush *m_pYellowGreenBrush;
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
&m_pBlackBrush
);
}
// Create a solid color brush with its rgb value 0x9ACD32.
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),
&m_pYellowGreenBrush
);
}
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pYellowGreenBrush);
m_pRenderTarget->DrawRectangle(&rcBrushRect, m_pBlackBrush, 1, NULL);
A differenza di altri pennelli, la creazione di un ID2D1SolidColorBrush è un'operazione relativamente economica. È possibile creare ID2D1SolidColorBrush oggetti ogni volta che si esegue il rendering senza alcun impatto sulle prestazioni. Questo approccio non è consigliato per i pennelli di sfumatura o i pennelli bitmap.
Uso di pennelli a gradiente lineare
Un ID2D1LinearGradientBrush disegna un'area con una sfumatura lineare definita lungo una linea, l'asse delle sfumature. Specifica i colori della sfumatura e la loro posizione lungo l'asse della sfumatura usando ID2D1GradientStop. È anche possibile modificare l'asse delle sfumature, che consente di creare sfumature orizzontali e verticali e di invertire la direzione della sfumatura. Per creare un pennello sfumatura lineare, chiamare il metodo ID2D1RenderTarget::CreateLinearGradientBrush.
La figura seguente mostra un quadrato disegnato con un ID2D1LinearGradientBrush con due colori predefiniti, "Giallo" e "ForestGreen".
Per creare la sfumatura illustrata nella figura precedente, completare questi passaggi:
Dichiarare due oggetti D2D1_GRADIENT_STOP. Ogni interruzione di sfumatura specifica un colore e una posizione. Una posizione di 0,0 indica l'inizio della sfumatura, mentre una posizione di 1,0 indica la fine della sfumatura.
Il codice seguente crea una matrice di due oggetti D2D1_GRADIENT_STOP. La prima specifica il colore "Giallo" alla posizione 0, e la seconda specifica il colore "ForestGreen" alla posizione 1.
// Create an array of gradient stops to put in the gradient stop
// collection that will be used in the gradient brush.
ID2D1GradientStopCollection *pGradientStops = NULL;
D2D1_GRADIENT_STOP gradientStops[2];
gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow, 1);
gradientStops[0].position = 0.0f;
gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::ForestGreen, 1);
gradientStops[1].position = 1.0f;
- Creare un ID2D1GradientStopCollection. Nell'esempio seguente viene chiamato CreateGradientStopCollection, passando la matrice di oggetti D2D1_GRADIENT_STOP, il numero di stop di gradiente (2), D2D1_GAMMA_2_2 per l'interpolazione e D2D1_EXTEND_MODE_CLAMP per la modalità di estensione.
// Create the ID2D1GradientStopCollection from a previously
// declared array of D2D1_GRADIENT_STOP structs.
hr = m_pRenderTarget->CreateGradientStopCollection(
gradientStops,
2,
D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE_CLAMP,
&pGradientStops
);
- Crea il ID2D1LinearGradientBrush. Nel prossimo esempio viene chiamato il metodo CreateLinearGradientBrush e gli vengono passate le proprietà del pennello sfumatura lineare che contengono il punto iniziale in (0, 0), il punto finale in (150, 150) e gli stop di sfumatura creati nel passaggio precedente.
// The line that determines the direction of the gradient starts at
// the upper-left corner of the square and ends at the lower-right corner.
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(
D2D1::Point2F(0, 0),
D2D1::Point2F(150, 150)),
pGradientStops,
&m_pLinearGradientBrush
);
}
- Usare l'ID2D1LinearGradientBrush. Nell'esempio di codice successivo viene usato il pennello per riempire un rettangolo.
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pLinearGradientBrush);
Ulteriori informazioni sui punti del gradiente
Il D2D1_GRADIENT_STOP è l'elemento fondamentale di un pennello per sfumature. Un punto di arresto della sfumatura specifica il colore e la posizione lungo l'asse della sfumatura. Il valore della posizione della sfumatura è compreso tra 0,0 e 1,0. Più vicino è a 0,0, più il colore è più vicino all'inizio della sfumatura; più vicino è a 1,0, più il colore è più vicino alla fine della sfumatura.
Nell'illustrazione seguente vengono evidenziate le interruzioni di gradiente. Il cerchio contrassegna la posizione delle interruzioni di gradiente e una linea tratteggiata mostra l'asse del gradiente.
Il primo punto di fermata del gradiente specifica il colore giallo alla posizione 0,0. Il secondo punto di tappa del gradiente specifica il colore rosso in una posizione pari a 0,25. Da sinistra a destra lungo l'asse del gradiente, i colori tra questi due stop gradualmente cambiano dal giallo al rosso. Il terzo punto di arresto della sfumatura specifica il colore blu in una posizione di 0,75. I colori tra il secondo e il terzo punto di gradiente cambiano gradualmente da rosso a blu. Il quarto punto di sfumatura specifica il verde lime in una posizione di 1,0. I colori tra il terzo e il quarto punto del gradiente cambiano gradualmente dal blu al verde chiaro.
Asse del gradiente
Come accennato in precedenza, le interruzioni di colore di un pennello di gradiente lineare vengono posizionate lungo una linea, l'asse del gradiente. È possibile specificare l'orientamento e le dimensioni della linea utilizzando i campi startPoint e endPoint della struttura D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES quando si crea un pennello a gradiente lineare. Dopo aver creato un pennello, è possibile modificare l'asse delle sfumature chiamando i metodi SetStartPoint e SetEndPoint. Modificando il punto iniziale e il punto finale del pennello, è possibile creare sfumature orizzontali e verticali, invertire la direzione della sfumatura e altro ancora.
Nell'illustrazione seguente, ad esempio, il punto iniziale è impostato su (0,0) e il punto finale su (150, 50); in questo modo viene creata una sfumatura diagonale che inizia nell'angolo superiore sinistro e si estende all'angolo inferiore destro dell'area da disegnare. Quando si imposta il punto iniziale su (0, 25) e il punto finale su (150, 25), viene creata una sfumatura orizzontale. Analogamente, l'impostazione del punto iniziale su (75, 0) e il punto finale su (75, 50) crea una sfumatura verticale. L'impostazione del punto iniziale su (0, 50) e il punto finale su (150, 0) crea una sfumatura diagonale che inizia nell'angolo inferiore sinistro e si estende all'angolo superiore destro dell'area da disegnare.
Uso dei pennelli a sfumatura radiale
A differenza di un ID2D1LinearGradientBrush, che combina due o più colori lungo un asse sfumato, un ID2D1RadialGradientBrush disegna un'area con una sfumatura radiale che combina due o più colori in un'ellisse. Mentre un ID2D1LinearGradientBrush definisce l'asse delle sfumature con un punto iniziale e un punto finale, un ID2D1RadialGradientBrush definisce l'ellisse sfumatura specificando un punto centrale, orizzontale e verticale e un offset di origine sfumatura.
Analogamente a un ID2D1LinearGradientBrush, un ID2D1RadialGradientBrush usa un ID2D1GradientStopCollection per definire i colori e le posizioni nella sfumatura.
La figura seguente mostra un cerchio disegnato con un ID2D1RadialGradientBrush. Il cerchio ha due punti di sfumatura: il primo specifica un colore predefinito "Giallo" in una posizione di 0,0 e il secondo specifica un colore predefinito "ForestGreen" in una posizione di 1,0. La sfumatura ha un centro di (75, 75), un'origine della sfumatura con offset pari a (0, 0) e un raggio x e un raggio y di 75.
Gli esempi di codice seguenti illustrano come disegnare questo cerchio con un ID2D1RadialGradientBrush con due punti di colore: "Giallo" in una posizione di 0,0 e "ForestGreen" in una posizione di 1,0. Analogamente alla creazione di un ID2D1LinearGradientBrush, l'esempio chiama CreateGradientStopCollection per creare una ID2D1GradientStopCollection da un array di fermate del gradiente.
// Create an array of gradient stops to put in the gradient stop
// collection that will be used in the gradient brush.
ID2D1GradientStopCollection *pGradientStops = NULL;
D2D1_GRADIENT_STOP gradientStops[2];
gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow, 1);
gradientStops[0].position = 0.0f;
gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::ForestGreen, 1);
gradientStops[1].position = 1.0f;
// Create the ID2D1GradientStopCollection from a previously
// declared array of D2D1_GRADIENT_STOP structs.
hr = m_pRenderTarget->CreateGradientStopCollection(
gradientStops,
2,
D2D1_GAMMA_2_2,
D2D1_EXTEND_MODE_CLAMP,
&pGradientStops
);
Per creare un ID2D1RadialGradientBrush, usare il metodo ID2D1RenderTarget::CreateRadialGradientBrush. Il CreateRadialGradientBrush accetta tre parametri. Il primo parametro, un D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES specifica il centro, l'offset dell'origine sfumatura e i raggi orizzontale e verticale della sfumatura. Il secondo parametro è un ID2D1GradientStopCollection che descrive i colori e le relative posizioni nella sfumatura, e il terzo parametro è l'indirizzo del puntatore che riceve il riferimento al nuovo ID2D1RadialGradientBrush. Alcuni sovraccarichi accettano un parametro aggiuntivo, una struttura D2D1_BRUSH_PROPERTIES che specifica un valore di opacità e una trasformazione da applicare al nuovo pennello.
Nell'esempio seguente viene chiamato CreateRadialGradientBrush, passando la matrice delle fermate del gradiente e le proprietà del pennello sfumatura radiale, avente il valore del centro impostato a (75, 75), il gradientOriginOffset impostato a (0, 0), e radiusX e radiusY entrambi impostati a 75.
// The center of the gradient is in the center of the box.
// The gradient origin offset was set to zero(0, 0) or center in this case.
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateRadialGradientBrush(
D2D1::RadialGradientBrushProperties(
D2D1::Point2F(75, 75),
D2D1::Point2F(0, 0),
75,
75),
pGradientStops,
&m_pRadialGradientBrush
);
}
L'esempio finale usa il pennello per riempire un'ellisse.
m_pRenderTarget->FillEllipse(ellipse, m_pRadialGradientBrush);
m_pRenderTarget->DrawEllipse(ellipse, m_pBlackBrush, 1, NULL);
Configurazione di una sfumatura radiale
Valori diversi per centro, gradientOriginOffset, radiusX e/o radiusY producono sfumature diverse. La figura seguente mostra diverse sfumature radiali con offset di origine sfumatura diversi, creando l'aspetto della luce che illumina i cerchi da diverse angolazioni.
Uso di pennelli bitmap
Un ID2D1BitmapBrush disegna un'area con una bitmap (rappresentata da un oggetto ID2D1Bitmap).
La figura seguente mostra un quadrato dipinto con una bitmap di una pianta.
Gli esempi seguenti illustrano come disegnare questo quadrato con un ID2D1BitmapBrush.
Il primo esempio inizializza un ID2D1Bitmap da usare con il pennello. Il ID2D1Bitmap viene fornito da un metodo helper, LoadResourceBitmap, definito altrove nell'esempio.
// Create the bitmap to be used by the bitmap brush.
if (SUCCEEDED(hr))
{
hr = LoadResourceBitmap(
m_pRenderTarget,
m_pWICFactory,
L"FERN",
L"Image",
&m_pBitmap
);
}
Per creare il pennello bitmap, chiamare il metodo ID2D1RenderTarget::CreateBitmapBrush e specificare il ID2D1Bitmap con cui disegnare. Il metodo restituisce un HRESULT e un oggetto ID2D1BitmapBrush. Alcuni overload di CreateBitmapBrush consentono di specificare opzioni aggiuntive accettando un D2D1_BRUSH_PROPERTIES e una struttura D2D1_BITMAP_BRUSH_PROPERTIES.
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateBitmapBrush(
m_pBitmap,
&m_pBitmapBrush
);
}
Nell'esempio seguente viene utilizzato il pennello per riempire un rettangolo.
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pBitmapBrush);
Configurazione delle modalità di estensione
In alcuni casi, la sfumatura di un pennello sfumato o la bitmap per un pennello bitmap non riempie completamente l'area da disegnare.
Quando ciò si verifica per un ID2D1BitmapBrush, Direct2D usa le impostazioni della modalità orizzontale del pennello (SetExtendModeX) e verticale (SetExtendModeY) per determinare come riempire l'area rimanente.
Quando ciò si verifica per un pennello sfumato, Direct2D determina come riempire l'area rimanente usando il valore del parametro D2D1_EXTEND_MODE specificato quando è stato chiamato il CreateGradientStopCollection per creare il pennello s ID2D1GradientStopCollection.
La figura seguente mostra i risultati di ogni possibile combinazione delle modalità di estensione per un ID2D1BitmapBrush: D2D1_EXTEND_MODE_CLAMP (CLAMP), D2D1_EXTEND_MODE_WRAP (WRAP) e D2D1_EXTEND_MIRROR (MIRROR).
Nell'esempio seguente viene illustrato come impostare le modalità x-extend e y-extend del pennello bitmap su D2D1_EXTEND_MIRROR. Disegna quindi il rettangolo con il ID2D1BitmapBrush.
m_pBitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_MIRROR);
m_pBitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_MIRROR);
m_pRenderTarget->FillRectangle(exampleRectangle, m_pBitmapBrush);
Genera un output come illustrato nella figura seguente.
Trasformazione di pennelli
Quando si dipinge con un pennello, si opera nello spazio delle coordinate del target di rendering. I pennelli non si posizionano automaticamente per allinearsi all'oggetto disegnato; per impostazione predefinita, iniziano a disegnare all'origine (0, 0) della destinazione di rendering.
È possibile "spostare" la sfumatura definita da un ID2D1LinearGradientBrush in un'area di destinazione regolando il punto iniziale e quello finale. Analogamente, è possibile spostare la sfumatura definita da un ID2D1RadialGradientBrush modificandone il centro e i raggi.
Per allineare il contenuto di un ID2D1BitmapBrush all'area da disegnare, è possibile utilizzare il metodo SetTransform per convertire la bitmap nella posizione desiderata. Questa trasformazione influisce solo sul pennello; non influisce su altri contenuti disegnati dalla destinazione di rendering.
Le illustrazioni seguenti illustrano l'effetto dell'uso di un ID2D1BitmapBrush per riempire un rettangolo situato in (100, 100). L'illustrazione a sinistra mostra il risultato del riempimento del rettangolo senza trasformare il pennello: la bitmap viene disegnata all'origine della destinazione di rendering. Di conseguenza, solo una parte della bitmap viene visualizzata nel rettangolo. La figura a destra mostra il risultato della trasformazione del ID2D1BitmapBrush, in modo che il relativo contenuto venga spostato di 50 pixel a destra e di 50 pixel verso il basso. La bitmap ora riempie il rettangolo.
Il codice seguente illustra come eseguire questa operazione. Applicare prima una traduzione all'ID2D1BitmapBrush, spostando il pennello di 50 pixel lungo l'asse x e 50 pixel verso il basso lungo l'asse y. Usare quindi il ID2D1BitmapBrush per riempire il rettangolo con l'angolo superiore sinistro in (100, 100) e l'angolo inferiore destro in (200, 200).
// Create the bitmap to be used by the bitmap brush.
if (SUCCEEDED(hr))
{
hr = LoadResourceBitmap(
m_pRenderTarget,
m_pWICFactory,
L"FERN",
L"Image",
&m_pBitmap
);
}
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateBitmapBrush(
m_pBitmap,
&m_pBitmapBrush
);
}
D2D1_RECT_F rcTransformedBrushRect = D2D1::RectF(100, 100, 200, 200);
// Demonstrate the effect of transforming a bitmap brush.
m_pBitmapBrush->SetTransform(
D2D1::Matrix3x2F::Translation(D2D1::SizeF(50,50))
);
// To see the content of the rcTransformedBrushRect, comment
// out this statement.
m_pRenderTarget->FillRectangle(
&rcTransformedBrushRect,
m_pBitmapBrush
);
m_pRenderTarget->DrawRectangle(rcTransformedBrushRect, m_pBlackBrush, 1, NULL);