-
> [16] Lacmus © (14.09.07 23:58)
Работает только для углов до 90°?
-
>homm © (15.09.07 00:53) [19]
Классно, хотя почему вычисляется тангенс 90 градусов без ошибки остается загадкой
>homm © (15.09.07 00:54) [20]
Там и с ClipRect тоже есть проблемы - он не выставлен
-
На основе homm © (15.09.07 00:53) [19]
procedure DrawAngleGradient(aCanvas: TCanvas; aRect: TRect; aColor1, aColor2: TColor; aAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
Bitmap: TBitmap;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C: Extended;
Line: ^RGBQuadArray;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
Bitmap := TBitmap.Create;
try
Bitmap.HandleType := bmDIB;
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(W, H);
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinCos(aAngle * PI / 180, SinA, CosA);
C := W * SinA + H * CosA;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR) / C;
CoeffG := (GetGValue(aColor2) - FromG) / C;
CoeffB := (GetBValue(aColor2) - FromB) / C;
for i := 0 to H - 1 do begin
Line := Bitmap.ScanLine[i];
if bBottomToTop then
k := H - i
else
k := i;
for j := 0 to W - 1 do begin
C := j * SinA + k * CosA;
Line[j].rgbRed := FromR + Round(C * CoeffR);
Line[j].rgbGreen := FromG + Round(C * CoeffG);
Line[j].rgbBlue := FromB + Round(C * CoeffB);
end
end;
BitBlt(aCanvas.Handle, aRect.Left, aRect.Top, W, H, Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
finally
Bitmap.Free
end
end;
-
Спасибо :) все-же я сам видимо не так силен в геметрии (или в логике, раз не смог додуматься до более простого варианта). Но я пошел еще дальше ;) procedure DrawAngleGradient(aCanvas: TCanvas; aRect: TRect; aColor1, aColor2: TColor; aAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
Bitmap: TBitmap;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C: Integer;
Line: ^RGBQuadArray;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
Bitmap := TBitmap.Create;
try
Bitmap.HandleType := bmDIB;
Bitmap.PixelFormat := pf32bit;
Bitmap.Width := W;
Bitmap.Height := H;
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinA := round(sin(aAngle * PI / 180)*256);
CosA := round(cos(aAngle * PI / 180)*256);
C := W * SinA + H * CosA;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR)*256 div (C shr 8);
CoeffG := (GetGValue(aColor2) - FromG)*256 div (C shr 8);
CoeffB := (GetBValue(aColor2) - FromB)*256 div (C shr 8);
for i := 0 to H - 1 do begin
Line := Bitmap.ScanLine[i];
if bBottomToTop then
k := H - i
else
k := i;
for j := 0 to W - 1 do begin
C := j * SinA + k * CosA;
Line[j].rgbRed := FromR + ((C * CoeffR) shr 16);
Line[j].rgbGreen := FromG + ((C * CoeffG) shr 16);
Line[j].rgbBlue := FromB + ((C * CoeffB) shr 16);
end;
end;
BitBlt(aCanvas.Handle, aRect.Left, aRect.Top, W, H, Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
finally
Bitmap.Free
end;
end; мой старый вариант на тестовой сцене — 2050мс, вариант из [22] — 1150мс, этот ваиант — 310мс.
-
homm © k * CosA; можно вынести в первый цикл, будет еще чуть быстрее:)
-
> [24] antonn © (15.09.07 22:43)
Даже нескольких процентов не получилось :) Тем не менее точность повысил точность. procedure DrawAngleGradient(aCanvas: TCanvas; aRect: TRect; aColor1, aColor2: TColor; aAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
Bitmap: TBitmap;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C, C1: Integer;
Line: ^RGBQuadArray;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
Bitmap := TBitmap.Create;
try
Bitmap.HandleType := bmDIB;
Bitmap.PixelFormat := pf32bit;
Bitmap.Width := W;
Bitmap.Height := H;
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinA := round(sin(aAngle * PI / 180)*4096);
CosA := round(cos(aAngle * PI / 180)*4096);
C := (W * SinA + H * CosA) shr 12;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR)*4096 div C;
CoeffG := (GetGValue(aColor2) - FromG)*4096 div C;
CoeffB := (GetBValue(aColor2) - FromB)*4096 div C;
for i := 0 to H - 1 do begin
Line := Bitmap.ScanLine[i];
if bBottomToTop then
k := (H - i) * CosA
else
k := i * CosA;
for j := 0 to W - 1 do begin
C := j * SinA + k;
Line[j].rgbRed := FromR + ((C * CoeffR) shr 24);
Line[j].rgbGreen := FromG + ((C * CoeffG) shr 24);
Line[j].rgbBlue := FromB + ((C * CoeffB) shr 24);
end;
end;
BitBlt(aCanvas.Handle, aRect.Left, aRect.Top, W, H, Bitmap.Canvas.Handle, 0, 0, SRCCOPY)
finally
Bitmap.Free
end;
end;
-
> homm © (15.09.07 22:55) [25]
Вот так побыстрее процентов на 20:
procedure DrawAngleGradient2(DC: HDC; ARect: TRect; AColor1, AColor2: TColor; AAngle: Integer);
type
RGBQuadArray = array[0..0] of TRGBQuad;
var
FromR, FromG, FromB: Byte;
bBottomToTop: Boolean;
i, j, k, W, H: Integer;
CoeffR, CoeffG, CoeffB, SinA, CosA, C: Integer;
Line: ^RGBQuadArray;
bmi: BITMAPINFO;
PBits: pointer;
MemDC: HDC;
MemBmp: HBITMAP;
LineBytes: integer;
nRow: integer;
function BytesPerScanline(PixelsPerScanline, BitsPerPixel, Alignment: Longint): Longint;
begin
Dec(Alignment);
Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;
Result := Result div 8;
end;
function GetScanLine(bmi: BITMAPINFO; Bits: pointer; Row: Integer): Pointer;
var
nRow: integer;
begin
if bmi.bmiHeader.biHeight > 0 then
nRow := bmi.bmiHeader.biHeight - Row - 1
else
nRow := Row;
Integer(Result) := Integer(Bits) + nRow * BytesPerScanline(bmi.bmiHeader.biWidth, bmi.bmiHeader.biBitCount, 32);
end;
begin
W := aRect.Right - aRect.Left;
H := aRect.Bottom - aRect.Top;
ZeroMemory(@bmi, sizeof(bmi));
bmi.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biCompression := BI_RGB;
bmi.bmiHeader.biBitCount := 32;
bmi.bmiHeader.biPlanes := 1;
bmi.bmiHeader.biWidth := w;
bmi.bmiHeader.biHeight := h;
bmi.bmiHeader.biSizeImage := 0;
bmi.bmiHeader.biClrUsed :=0;
bmi.bmiHeader.biClrImportant:=0;
MemDC := CreateCompatibleDC(DC);
MemBmp := CreateDIBSection(MemDC, bmi, DIB_RGB_COLORS, pBits, 0, 0);
SelectObject(MemDC, MemBmp);
aAngle := aAngle mod 360;
if aAngle < 0 then
aAngle := aAngle + 360;
if (aAngle >= 180) then begin
i := aColor1;
aColor1 := aColor2;
aColor2 := i;
aAngle := aAngle - 180;
end;
bBottomToTop := (aAngle > 90) and (aAngle < 180);
if bBottomToTop then
aAngle := 180 - aAngle;
SinA := round(sin(AAngle * PI / 180) * 4096);
CosA := round(cos(AAngle * PI / 180) * 4096);
C := (W * SinA + H * CosA) shr 12;
FromR := GetRValue(AColor1);
FromG := GetGValue(AColor1);
FromB := GetBValue(AColor1);
CoeffR := (GetRValue(aColor2) - FromR) * 4096 div C;
CoeffG := (GetGValue(aColor2) - FromG) * 4096 div C;
CoeffB := (GetBValue(aColor2) - FromB) * 4096 div C;
for i := 0 to H - 1 do begin
Line := GetScanLine(bmi, pBits, i);
if bBottomToTop then
k := (H - i) * CosA
else
k := i * CosA;
for j := 0 to W - 1 do begin
C := j * SinA + k;
Line[j].rgbRed := FromR + ((C * CoeffR) shr 24);
Line[j].rgbGreen := FromG + ((C * CoeffG) shr 24);
Line[j].rgbBlue := FromB + ((C * CoeffB) shr 24);
end;
end;
BitBlt(DC, ARect.Left, ARect.Top, W, H, MemDC, 0, 0, SRCCOPY);
DeleteObject(MemBmp);
DeleteObject(MemDC);
end;
А для углов кратных 90 надо вообще по другому действовать - можно в 10-20 раз быстрее залить.
|