Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Esta visão geral descreve como criar e usar ID2D1SolidColorBrush, ID2D1LinearGradientBrush, ID2D1RadialGradientBrushe ID2D1BitmapBrush objetos para pintar áreas com cores sólidas, gradientes e bitmaps. Ele contém as seções a seguir.
Pré-requisitos
Essa 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 sua saída. Pincéis diferentes 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.
Nota
A partir do Windows 8, você também pode usar o ID2D1ImageBrush, que é semelhante a um pincel bitmap, mas também pode usar primitivos.
Todos os pincéis herdam de ID2D1Brush e compartilham um conjunto de recursos comuns (configuração e obtenção de opacidade e transformação de 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 sobre cores
Antes de pintar com um ID2D1SolidColorBrush ou um pincel de gradiente, você precisa escolher cores. No Direct2D, as cores são representadas pela estrutura de 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 a 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 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 por conta própria ou 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, ele será padronizado como 1,0.
Use o construtorColorF(Enum, FLOAT)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 hexadecimal. Para obter uma lista completa de cores predefinidas, consulte a seção Constantes de cores 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 construtor ColorF(FLOAT, FLOAT, FLOAT, FLOAT) para especificar uma cor na sequência de um vermelho, verde, azul e alfa, em que cada elemento tem um valor entre 0,0 e 1,0.
O exemplo a seguir especifica os valores vermelho, verde, azul e alfa para uma cor.
ID2D1SolidColorBrush *pGridBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
&pGridBrush
);
- Use o construtor ColorF(UINT32, FLOAT) 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 você usa um pincel, os valores de D2D1_COLOR_F são sempre interpretados como alfa direto.
Usando pincéis de cores sólidas
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 traçado com um pincel de cor preta e pintado com uma cor sólida de valor 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 sempre que renderizar com pouco ou nenhum impacto no desempenho. Essa abordagem não é recomendada para pincéis de gradiente ou bitmap.
Como usar pincéis de gradiente linear
Um ID2D1LinearGradientBrush pinta uma área com um gradiente linear definido ao longo de uma linha, o eixo do gradiente. Especifique as cores do gradiente e sua localização ao longo do eixo do gradiente usando objetos ID2D1GradientStop . Você também pode modificar o eixo de gradiente, que permite criar gradiente horizontal e vertical e reverter 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 final do gradiente.
O código a seguir cria uma matriz de dois objetos D2D1_GRADIENT_STOP. A primeira marca especifica a cor "Yellow" na posição 0, e a segunda marca especifica a cor "ForesGreen" 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, transmitindo a matriz de objetos D2D1_GRADIENT_STOP, o número de marcas 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 exemplo a seguir chama o método CreateLinearGradientBrush e passa as propriedades de 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 marcas de gradiente
D2D1_GRADIENT_STOP é um bloco de construção básico de um pincel de gradiente. Uma marca 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 perto for de 0,0, mais próxima a cor estará do início do gradiente; quanto mais perto for de 1,0, mais próxima a cor estará do final do gradiente.
A ilustração a seguir realça as marcas de gradiente. O círculo marca a posição das paradas de gradiente e uma linha tracejada mostra o eixo do gradiente.
O primeiro ponto de parada do gradiente especifica a cor amarela na posição 0,0. A segunda marca de gradiente especifica a cor vermelha em uma posição de 0,25. Da esquerda para a direita ao longo do eixo gradiente, as cores entre essas duas paradas mudam gradualmente de amarelo para vermelho. A terceira marca de gradiente especifica a cor azul na posição 0,75. As cores entre o segundo e o terceiro ponto do gradiente mudam gradualmente de vermelho para azul. A quarta marca de gradiente especifica verde-limão na posição 1,0. As cores entre a terceira e a quarta marcas de gradiente mudam gradualmente de azul para verde-limão.
O eixo do gradiente
Conforme mencionado anteriormente, as marcas de gradiente de um pincel de gradiente linear são posicionadas ao longo de uma linha, 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, você pode ajustar o eixo de gradiente chamando os métodos SetStartPoint e SetEndPoint do pincel. Manipulando o ponto inicial e o ponto de extremidade 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.
Como usar os pincéis de gradiente radial
Ao contrário de um ID2D1LinearGradientBrush, que mescla duas ou mais cores ao longo de um eixo gradiente, um ID2D1RadialGradientBrush pinta uma área com um gradiente radial que mescla duas ou mais cores ao longo de uma elipse. Enquanto um ID2D1LinearGradientBrush define seu eixo de gradiente com um ponto inicial e um ponto de extremidade, um ID2D1RadialGradientBrush define sua elipse de gradiente especificando um radii central, horizontal e vertical e um deslocamento de origem gradiente.
Como um ID2D1LinearGradientBrush, um ID2D1RadialGradientBrush usa uma ID2D1GradientStopCollection para especificar as cores e as posições no gradiente.
A ilustração abaixo mostra um círculo colorido com ID2D1RadialGradientBrush. O círculo tem duas marcas de gradiente: a primeira especifica a cor predefinida "Yellow" na posição 0,0 e a segunda especifica a cor predefinida "ForestGreen" na posição 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 marcas de cor: "Yelllow" na posição 0,0 e "ForestGreen" na posição 1,0. Semelhante à criação de um ID2D1LinearGradientBrush, o exemplo chama CreateGradientStopCollection para criar uma ID2D1GradientStopCollection a partir de uma matriz de marcas 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 da 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 ID2D1RadialGradientBrush. Algumas sobrecargas exigem um parâmetro adicional, uma estrutura D2D1_BRUSH_PROPERTIES que especifica um valor de opacidade e uma transformação a ser aplicada ao novo pincel.
O próximo exemplo chama CreateRadialGradientBrush, transmitindo a matriz de marcas de gradiente e as propriedades do pincel de gradiente radial com o valor center definido como (75, 75), gradientOriginOffset definido como (0, 0) e radiusX e 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 seguinte mostra vários gradientes radiais com diferentes deslocamentos de origem, criando a impressão de que a luz ilumina os círculos de ângulos diferentes.
Como usar pincéis de bitmap
Um ID2D1BitmapBrush pinta uma área com um bitmap (representado por um objeto 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 ID2D1RenderTarget::CreateBitmapBrush e especifique o ID2D1Bitmap com o qual pintar. O método retorna um HRESULT e um objeto ID2D1BitmapBrush. Algumas sobrecargas de CreateBitmapBrush permitem que você especifique opções adicionais aceitando uma estrutura 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 para um pincel de bitmap não preenche completamente a área que está sendo pintada.
Quando isso acontece para um ID2D1BitmapBrush, o Direct2D usa as configurações de modo de extensão horizontal (SetExtendModeX) e vertical (SetExtendModeY) 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 especificado quando você chamou o CreateGradientStopCollection para criar o ID2D1GradientStopCollectiondo pincel de gradiente.
A ilustração a seguir mostra 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, ele 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);
A saída é produzida conforme mostrado na ilustração a seguir.
Como transformar pincéis
Quando você pinta com um pincel, ele pinta no espaço de coordenadas do destino de renderização. Pincéis não se posicionam automaticamente para se alinharem ao 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 de extremidade. Da mesma forma, você pode mover o gradiente definido por um ID2D1RadialGradientBrush alterando seu centro e raio.
Para alinhar o conteúdo de um ID2D1BitmapBrush à área que está sendo pintada, você pode usar o métodoSetTransform para traduzir o bitmap para o local desejado. Essa transformação afeta apenas o pincel; ele não afeta nenhum outro conteúdo desenhado pelo destino de renderização.
As ilustrações a seguir mostram o efeito de usar 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 conversão para ID2D1BitmapBrush, movendo 50 pixels do pincel 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);