PROG.

GR32 (TBitmap32) 에서 Gradient Fill

NUL 2010. 11. 15. 18:44

Graphics32
 는 델파이를 사용하는 사람중에서는 모를 사람이 없을 정도로 유명한 라이브러리입니다.


Gradient Fill 을 구현할 경우 Angus Johnson 님의 GR32_Lines/GR32_Text 를 쓰면 대부분의 Gradient 를 구현할 수 있습니다. (Gradient 이외에도 유용한 기능이 많죠)


다만 속도가 문제인데요. 비교적 단순한 Gradient 효과를 주기 위한 용도로는 조금 느린감이 있습니다.

그렇다고 인라인 어셈블리어로 대체할 능력은 안되기 때문에... 저는 윈도우 API를 사용합니다.

function GradientFill; external msimg32 name 'GradientFill';


윈도우 2000 부터 지원하는걸로 알고 있고요.

제가 만들어 쓰는 GUI 용 컴포넌트들은 이걸 많이 사용합니다.


이 함수를 비롯한 여타의 GDI 함수를 Bitmap32에 적용할 때의 문제점은 알파값이 누락 되는데 있습니다.
(혹 가능한 방법이 있을지는 모르겠네요)

그래서 API 를 쓰고 해당 부분의 알파 값을 재지정 하는 단순무식한 방법을 쓰곤 합니다 -_-;


아래는 가로 방향 Gradient 의 한 예 입니다.
procedure JnGradientFillHor(BMP: TBitmap32; const R: TRect; const B, C1, C2: TColor32);
var  
  TriVertex: array[0..1] of TTriVertex;  
  GradRect: array[0..1] of TGradientRect;
  i: Integer;
  P: PColor32;
begin
  GradRect[0].UpperLeft := 0;
  GradRect[0].LowerRight := 1;
  GradRect[1].UpperLeft := 1;
  GradRect[1].LowerRight := 2;
  TriVertex[0].Red :=   (C1 and $00FF0000) shr 8;
  TriVertex[0].Green := (C1 and $0000FF00);
  TriVertex[0].Blue :=  (C1 and $000000FF) shl 8;
  TriVertex[1].Red :=   (C2 and $00FF0000) shr 8;
  TriVertex[1].Green := (C2 and $0000FF00);
  TriVertex[1].Blue :=  (C2 and $000000FF) shl 8;
  TriVertex[0].x := R.Left;  TriVertex[0].y := R.Top;
  TriVertex[1].x := R.Right;  TriVertex[1].y := R.Bottom;
  GradientFill(BMP.Canvas.Handle, @TriVertex[0], 2, @GradRect[0], 1, GRADIENT_FILL_RECT_H);
  
  P := @BMP.Bits[0];
  for i := 0 to BMP.Width * BMP.Height - 1 do
  begin
    P^ := P^ or $FF000000;
    Inc(P);
  end;

  BMP.FrameRectS(R, B);
end;
좌측이 GR32_Lines에서 제공하는 SimpleGradientFill 함수, 우측이 위의 함수를 사용한 결과입니다.




200x200 사이즈의 Gradient Fill 에서 속도 차이가 20배 가까이 나오네요 (단위는 nanosecond)


GradientFill 함수를 커스터마이징 하면 다양한 Gradient 효과를 줄수 있습니다.

다만 Radial Gradient Fill은 방법이 없네요.. 


아무튼 전 이런 식으로 쓰고 있답니다.