Visão geral de pincéis
Esta visão geral descreve como criar e usar ID2D1SolidColorBrush, ID2D1LinearGradientBrush, ID2D1RadialGradientBrushe ID2D1BitmapBrush objetos para pintar áreas com cores sólidas, gradientes e bitmaps. Contém as seguintes secções.
Pré-requisitos
Esta visão geral pressupõe que você esteja familiarizado com a estrutura de um aplicativo Direct2D básico, conforme descrito em Criar um aplicativo Direct2D simples.
Tipos de pincel
Um pincel "pinta" uma área com a sua saída. Diferentes escovas têm diferentes tipos de saída. O Direct2D fornece quatro tipos de pincel: ID2D1SolidColorBrush pinta uma área com uma cor sólida, ID2D1LinearGradientBrush com um gradiente linear, ID2D1RadialGradientBrush com um gradiente radial e ID2D1BitmapBrush com um bitmap.
Observação
A partir do Windows 8, você também pode usar ID2D1ImageBrush, que é semelhante a um pincel de bitmap, mas também pode usar primitivos.
Todos os pincéis herdam de ID2D1Brush e partilham um conjunto de características comuns (definir e obter opacidade e transformar pincéis); eles são criados por ID2D1RenderTarget e são recursos dependentes do dispositivo: seu aplicativo deve criar pincéis depois de inicializar o destino de renderização com o qual os pincéis serão usados e recriar os pincéis sempre que o destino de renderização precisar ser recriado. (Para obter mais informações sobre recursos, consulte Visão geral de recursos .)
A ilustração a seguir mostra exemplos de cada um dos diferentes tipos de pincel.
Noções básicas de cor
Antes de pintar com um ID2D1SolidColorBrush ou um pincel de gradiente, é necessário escolher as cores. No Direct2D, as cores são representadas pela estrutura D2D1_COLOR_F (que na verdade é apenas um novo nome para a estrutura usada pelo Direct3D, D3DCOLORVALUE).
Antes do Windows 8, D2D1_COLOR_F usa codificação sRGB. A codificação sRGB divide as cores em quatro componentes: vermelho, verde, azul e alfa. Cada componente é representado por um valor de ponto flutuante com um intervalo normal de 0,0 a 1,0. Um valor de 0,0 indica a ausência completa dessa cor, enquanto um valor de 1,0 indica que a cor está totalmente presente. Para o componente alfa, 0.0 representa uma cor totalmente transparente e 1.0 representa uma cor totalmente opaca.
A partir do Windows 8, D2D1_COLOR_F também aceita codificação scRGB. scRGB é um superconjunto de que permite valores de cor acima de 1,0 e abaixo de 0,0.
Para definir uma cor, você pode usar a estrutura D2D1_COLOR_F e inicializar seus campos você mesmo, ou você pode usar a classe D2D1::ColorF para ajudá-lo a criar a cor. A classe ColorF fornece vários construtores para definir cores. Se o valor alfa não for especificado nos construtores, o padrão será 1.0.
Use o ColorF(Enum, FLOAT) construtor para especificar uma cor predefinida e um valor de canal alfa. Um valor de canal alfa varia de 0,0 a 1,0, onde 0,0 representa uma cor totalmente transparente e 1,0 representa uma cor totalmente opaca. A ilustração a seguir mostra várias cores predefinidas e seus equivalentes hexadecimais. Para obter uma lista completa de cores predefinidas, consulte a seção Constantes de cor da classeColorF.
O exemplo a seguir cria uma cor predefinida e a usa para especificar a cor de um ID2D1SolidColorBrush.
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black, 1.0f),
&m_pBlackBrush
);
Use o construtorColorF(FLOAT, FLOAT, FLOAT, FLOAT) para especificar uma cor na sequência de vermelho, verde, azul e alfa, onde cada elemento tem um valor entre 0,0 e 1,0.
O exemplo a seguir especifica os valores vermelho, verde, azul e alfa de uma cor.
ID2D1SolidColorBrush *pGridBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
&pGridBrush
);
- Use o ColorF(UINT32, FLOAT) construtor para especificar o valor hexadecimal de uma cor e um valor alfa, conforme mostrado no exemplo a seguir.
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0x9ACD32, 1.0f)),
&m_pYellowGreenBrush
);
Modos alfa
Independentemente do modo alfa do destino de renderização com o qual se utiliza um pincel, os valores D2D1_COLOR_F são sempre interpretados como alfa direto.
Usando pincéis de cor sólida
Para criar um pincel de cor sólida, chame o método ID2D1RenderTarget::CreateSolidColorBrush, que retorna um HRESULT e um objeto ID2D1SolidColorBrush. A ilustração a seguir mostra um quadrado que é traçado com um pincel de cor preta e pintado com um pincel de cor sólida que tem o valor de cor de 0x9ACD32.
O código a seguir mostra como criar e usar um pincel de cor preta e um pincel com um valor de cor de 0x9ACD32 para preencher e desenhar esse quadrado.
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);
Ao contrário de outros pincéis, criar um ID2D1SolidColorBrush é uma operação relativamente barata. Você pode criar objetos ID2D1SolidColorBrush cada vez que renderizar, com um impacto mínimo ou nenhum impacto no desempenho. Essa abordagem não é recomendada para pincéis de gradiente ou bitmap.
Usando pincéis de gradiente linear
Um ID2D1LinearGradientBrush pinta uma área com um gradiente linear definido ao longo de uma linha, o eixo do gradiente. Você especifica as cores do gradiente e sua localização ao longo do eixo do gradiente usando ID2D1GradientStop objetos. Você também pode modificar o eixo do gradiente, o que permite criar gradientes horizontais e verticais e inverter a direção do gradiente. Para criar um pincel de gradiente linear, chame o método ID2D1RenderTarget::CreateLinearGradientBrush.
A ilustração a seguir mostra um quadrado pintado com um ID2D1LinearGradientBrush que tem duas cores predefinidas, "Yellow" e "ForestGreen".
Para criar o gradiente mostrado na ilustração anterior, conclua estas etapas:
Declare dois objetos D2D1_GRADIENT_STOP. Cada parada de gradiente especifica uma cor e uma posição. Uma posição de 0,0 indica o início do gradiente, enquanto uma posição de 1,0 indica o fim do gradiente.
O código a seguir cria uma matriz de dois objetos D2D1_GRADIENT_STOP. A primeira paragem especifica a cor "Amarelo" na posição 0 e a segunda paragem especifica a cor "ForestGreen" na posição 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;
- Crie um ID2D1GradientStopCollection. O exemplo a seguir chama CreateGradientStopCollection, passando a matriz de objetos D2D1_GRADIENT_STOP, o número de paradas de gradiente (2), D2D1_GAMMA_2_2 para interpolação e D2D1_EXTEND_MODE_CLAMP para o modo de extensão.
// 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
);
- Crie o ID2D1LinearGradientBrush. O próximo exemplo chama o métodoCreateLinearGradientBrush e passa a ele as propriedades do pincel de gradiente linear que contêm o ponto inicial em (0, 0) e o ponto final em (150, 150), e as paradas de gradiente criadas na etapa anterior.
// 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
);
}
- Use o ID2D1LinearGradientBrush. O próximo exemplo de código usa o pincel para preencher um retângulo.
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pLinearGradientBrush);
Mais sobre paradas de gradiente
O D2D1_GRADIENT_STOP é o bloco de construção básico de um pincel de gradiente. Uma parada de gradiente especifica a cor e a posição ao longo do eixo do gradiente. O valor da posição do gradiente varia entre 0,0 e 1,0. Quanto mais próximo de 0,0, mais próxima a cor está do início do gradiente; Quanto mais próximo de 1.0, mais próxima a cor está do final do gradiente.
A ilustração a seguir destaca os pontos de interrupção do gradiente. O círculo marca a posição das paradas de gradiente e uma linha tracejada mostra o eixo do gradiente.
A primeira paragem de gradiente especifica a cor amarela numa posição de 0,0. A segunda interrupção de gradiente especifica a cor vermelha numa posição de 0,25. Da esquerda para a direita ao longo do eixo do gradiente, as cores entre essas duas paradas mudam gradualmente de amarelo para vermelho. O terceiro ponto de gradiente especifica a cor azul na posição 0,75. As cores entre o segundo e o terceiro pontos de gradiente mudam gradualmente de vermelho para azul. A quarta paragem de gradiente especifica verde limão na posição 1,0. As cores entre o terceiro e o quarto ponto de gradiente mudam gradualmente de azul para verde limão.
O eixo do gradiente
Como mencionado anteriormente, os pontos de paragem de gradiente de um pincel com gradiente linear são posicionados ao longo de uma linha reta, o eixo do gradiente. Você pode especificar a orientação e o tamanho da linha usando os campos startPoint e endPoint da estrutura D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES ao criar um pincel de gradiente linear. Depois de criar um pincel, pode ajustar o eixo do gradiente chamando os métodos SetStartPoint e SetEndPoint do pincel. Ao manipular o ponto inicial e o ponto final do pincel, você pode criar gradientes horizontais e verticais, inverter a direção do gradiente e muito mais.
Por exemplo, na ilustração a seguir, o ponto inicial é definido como (0,0) e o ponto final como (150, 50); Isso cria um gradiente diagonal que começa no canto superior esquerdo e se estende até o canto inferior direito da área que está sendo pintada. Quando você define o ponto inicial como (0, 25) e o ponto final como (150, 25), um gradiente horizontal é criado. Da mesma forma, definir o ponto inicial como (75, 0) e o ponto final como (75, 50) cria um gradiente vertical. Definir o ponto inicial como (0, 50) e o ponto final como (150, 0) cria um gradiente diagonal que começa no canto inferior esquerdo e se estende até o canto superior direito da área que está sendo pintada.
Usando pincéis de gradiente radial
Ao contrário de um ID2D1LinearGradientBrush, que mistura duas ou mais cores ao longo de um eixo de gradiente, um ID2D1RadialGradientBrush pinta uma área com um gradiente radial que mistura duas ou mais cores em uma elipse. Enquanto um ID2D1LinearGradientBrush define seu eixo de gradiente com um ponto inicial e um ponto final, um ID2D1RadialGradientBrush define sua elipse de gradiente especificando um centro, raios horizontais e verticais e um deslocamento de origem de gradiente.
Como um ID2D1LinearGradientBrush, um ID2D1RadialGradientBrush usa um ID2D1GradientStopCollection para especificar as cores e posições no gradiente.
A ilustração a seguir mostra um círculo pintado com um ID2D1RadialGradientBrush. O círculo tem dois pontos de gradiente: o primeiro especifica uma cor predefinida "Amarelo" na posição de 0,0, e o segundo especifica uma cor predefinida "ForestGreen" na posição de 1,0. O gradiente tem um centro de (75, 75), um deslocamento de origem de gradiente de (0, 0) e um raio x e y de 75.
Os exemplos de código a seguir mostram como pintar esse círculo com um ID2D1RadialGradientBrush que tem duas paradas de cor: "Yellow" em uma posição de 0.0 e "ForestGreen" em uma posição de 1.0. Semelhante à criação de umID2D1LinearGradientBrush, o exemplo chama CreateGradientStopCollection para criar um ID2D1GradientStopCollection a partir de uma matriz de paradas de 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
);
Para criar um ID2D1RadialGradientBrush, use o método ID2D1RenderTarget::CreateRadialGradientBrush. O CreateRadialGradientBrush usa três parâmetros. O primeiro parâmetro, D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES, especifica o centro, o deslocamento de origem do gradiente e os raios horizontal e vertical do gradiente. O segundo parâmetro é um ID2D1GradientStopCollection que descreve as cores e suas posições no gradiente, e o terceiro parâmetro é o endereço do ponteiro que recebe a nova referência de ID2D1RadialGradientBrush. Algumas sobrecargas têm um parâmetro adicional, uma estrutura D2D1_BRUSH_PROPERTIES, que especifica um valor de opacidade e uma transformação a aplicar ao novo pincel.
O próximo exemplo chama CreateRadialGradientBrush, passando a matriz de paradas de gradiente e as propriedades do pincel de gradiente radial que têm o valor do centro definido como (75, 75), o gradientOriginOffset definido como (0, 0) e o radiusX e o radiusY ambos definidos como 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
);
}
O exemplo final usa o pincel para preencher uma elipse.
m_pRenderTarget->FillEllipse(ellipse, m_pRadialGradientBrush);
m_pRenderTarget->DrawEllipse(ellipse, m_pBlackBrush, 1, NULL);
Configurando um gradiente radial
Valores diferentes para centro, gradientOriginOffset, radiusX e/ou radiusY produzem gradientes diferentes. A ilustração a seguir mostra vários gradientes radiais com diferentes deslocamentos na origem do gradiente, criando a aparência de a luz iluminar os círculos de diferentes ângulos.
Usando pincéis de bitmap
Um ID2D1BitmapBrush pinta uma área com um bitmap (representado por um objeto de ID2D1Bitmap).
A ilustração a seguir mostra um quadrado pintado com um bitmap de uma planta.
Os exemplos a seguir mostram como pintar esse quadrado com um ID2D1BitmapBrush.
O primeiro exemplo inicializa um ID2D1Bitmap para uso com o pincel. O ID2D1Bitmap é fornecido por um método auxiliar, LoadResourceBitmap, definido em outro lugar no exemplo.
// 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
);
}
Para criar o pincel de bitmap, chame o método de ID2D1RenderTarget::CreateBitmapBrush e especifique oID2D1Bitmapcom o qual pintar. O método retorna um HRESULT e um ID2D1BitmapBrush objeto. Algumas sobrecargas de CreateBitmapBrush permitem que você especifique opções adicionais aceitando um D2D1_BRUSH_PROPERTIES e uma estrutura D2D1_BITMAP_BRUSH_PROPERTIES.
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateBitmapBrush(
m_pBitmap,
&m_pBitmapBrush
);
}
O próximo exemplo usa o pincel para preencher um retângulo.
m_pRenderTarget->FillRectangle(&rcBrushRect, m_pBitmapBrush);
Configurando modos de extensão
Às vezes, o gradiente de um pincel de gradiente ou o bitmap de um pincel de bitmap não preenche completamente a área a ser pintada.
Quando isso acontece para um ID2D1BitmapBrush, o Direct2D usa as configurações de modo de extensão horizontal (SetExtendModeX) e vertical (SetExtendModeY) do pincel para determinar como preencher a área restante.
Quando isso acontece para um pincel de gradiente, o Direct2D determina como preencher a área restante usando o valor do parâmetro D2D1_EXTEND_MODE que você especificou quando chamou o CreateGradientStopCollection para criar o ID2D1GradientStopCollection do pincel de gradiente ID2D1GradientStopCollection .
A ilustração seguinte apresenta os resultados de todas as combinações possíveis dos modos de extensão para um ID2D1BitmapBrush: D2D1_EXTEND_MODE_CLAMP (CLAMP), D2D1_EXTEND_MODE_WRAP (WRAP) e D2D1_EXTEND_MIRROR (MIRROR).
O exemplo a seguir mostra como definir os modos de extensão x e y do pincel de bitmap como D2D1_EXTEND_MIRROR. Em seguida, pinta o retângulo com o ID2D1BitmapBrush.
m_pBitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_MIRROR);
m_pBitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_MIRROR);
m_pRenderTarget->FillRectangle(exampleRectangle, m_pBitmapBrush);
Gera uma saída como mostrado na ilustração seguinte.
Transformando pincéis
Quando você pinta com um pincel, ele pinta no espaço de coordenadas do destino de renderização. Os pincéis não se posicionam automaticamente para se alinharem com o objeto que está sendo pintado; Por padrão, eles começam a pintar na origem (0, 0) do destino de renderização.
Você pode "mover" o gradiente definido por um ID2D1LinearGradientBrush para uma área de destino definindo seu ponto inicial e ponto final. Da mesma forma, você pode mover o gradiente definido por um ID2D1RadialGradientBrush alterando seu centro e raios.
Para alinhar o conteúdo de um ID2D1BitmapBrushdeà área a ser pintada, pode usar o método SetTransform para traduzir o bitmap para o local desejado. Esta transformação afeta apenas o pincel; ele não afeta qualquer outro conteúdo desenhado pelo destino de renderização.
As ilustrações a seguir mostram o efeito do uso de um ID2D1BitmapBrush para preencher um retângulo localizado em (100, 100). A ilustração à esquerda mostra o resultado do preenchimento do retângulo sem transformar o pincel: o bitmap é desenhado na origem do alvo de renderização. Como resultado, apenas uma parte do bitmap aparece no retângulo. A ilustração à direita mostra o resultado da transformação do ID2D1BitmapBrush para que seu conteúdo seja deslocado 50 pixels para a direita e 50 pixels para baixo. O bitmap agora preenche o retângulo.
O código a seguir mostra como fazer isso. Primeiro, aplique uma tradução ao ID2D1BitmapBrush, movendo o pincel 50 pixels para a direita ao longo do eixo x e 50 pixels para baixo ao longo do eixo y. Em seguida, use o ID2D1BitmapBrush para preencher o retângulo que tem o canto superior esquerdo em (100, 100) e o canto inferior direito em (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);