-
function MixerColors(FromColor, ToColor: TColor; Rate: Single): TColor;
var
ra, rb: byte;
begin
RA := round(Rate * 255);
RB := 255 - RA;
result := (((Lo(FromColor) * RA + Lo(ToColor) * RB) shr 8) or
(((Lo(FromColor shr 8) * RA + Lo(ToColor shr 8) * RB) shr 8) shl 8) or
(((Lo(FromColor shr 16) * RA + Lo(ToColor shr 16) * RB) shr 8) shl 16));
end;
procedure SetPixel(X : Integer; Y : Integer; Alpha : Double; ACanvas: TCanvas);
VAR
T: byte;
begin
ACanvas.Pixels[x,y] := MixerColors(ACanvas.Pen.Color, ACanvas.Pixels[x,y], Alpha);
end;
procedure DrawWuCircle(cx : Integer; cy : Integer; R : Integer; ACanvas: TCanvas);
var
X : Integer;
Y : Integer;
T : Double;
D : Double;
J : Integer;
KX : Integer;
KY : Integer;
LastX : Integer;
begin
x := R;
LastX := R;
y := 0;
T := 0;
J:=0;
while J<=3 do
begin
KX := J mod 2*2-1;
KY := J div 2 mod 2*2-1;
SetPixel(KX*x+cx, KY*y+cy, 1, ACanvas);
SetPixel(KX*y+cx, KY*x+cy, 1, ACanvas);
Inc(J);
end;
while x>y do
begin
y := y+1;
D := Ceil(Sqrt(R*R-y*y))-Sqrt(R*R-y*y);
if D<T then
begin
x := x-1;
end;
if x<y then
begin
Break;
end;
if (x=y) and (LastX=x) then
begin
Break;
end;
J:=0;
while J<=3 do
begin
KX := J mod 2*2-1;
KY := J div 2 mod 2*2-1;
SetPixel(KX*x+cx, KY*y+cy, 1-D, ACanvas);
SetPixel(KX*y+cx, KY*x+cy, 1-D, ACanvas);
if x-1>=y then
begin
SetPixel(KX*(x-1)+cx, KY*y+cy, D, ACanvas);
SetPixel(KX*y+cx, KY*(x-1)+cy, D, ACanvas);
end;
Inc(J);
end;
T := D;
LastX := X;
end;
end;
-
А вот то же самое (черновой вариант) со сканлайнами
procedure DrawCircle1(DC: HDC; CX, CY, R: Integer; Color: TColor);
type
RGBTripleArray = array[0..0] of TRGBTriple;
var
oldpt, pt: tpoint;
bmi: BITMAPINFO;
PBits: pointer;
MemDC: HDC;
MemBmp: HBITMAP;
w,h: integer;
X : Integer;
Y : Integer;
T : Double;
D : Double;
J : Integer;
KX : Integer;
KY : Integer;
LastX : Integer;
res: integer;
rgn: HRGN;
function MixerColors(FromColor, ToColor: TColor; Rate: Single): TColor;
var
ra, rb: byte;
begin
RA := round(Rate * 255);
RB := 255 - RA;
result := (((Lo(FromColor) * RA + Lo(ToColor) * RB) shr 8) or
(((Lo(FromColor shr 8) * RA + Lo(ToColor shr 8) * RB) shr 8) shl 8) or
(((Lo(FromColor shr 16) * RA + Lo(ToColor shr 16) * RB) shr 8) shl 16));
end;
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
result := nil;
if (Row < 0) or (Row >= bmi.bmiHeader.biHeight) then exit;
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;
procedure SetPixel(bmi: BITMAPINFO; Bits: pointer; X : Integer; Y : Integer; Alpha : Double; Color: TColor);
var
Line: ^RGBTripleArray;
BkColor: TColor;
NewColor: TColor;
begin
Line := GetScanLine(bmi, Bits, Y);
if not assigned(line) then exit;
if (x<0) or (x>=bmi.bmiHeader.biWidth) then exit;
BkColor := RGB(Line[x].rgbtRed, Line[x].rgbtGreen, Line[x].rgbtBlue);
NewColor := MixerColors(COLOR, BkColor, alpha);
Line[x].rgbtRed := GetRValue(NewColor);
Line[x].rgbtGreen := GetgValue(NewColor);
Line[x].rgbtBlue := GetbValue(NewColor);
end;
begin
if (r <= 0) then exit;
W := 2 * r;
H := 2 * r;
ZeroMemory(@bmi, sizeof(bmi));
bmi.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biCompression := BI_RGB;
bmi.bmiHeader.biBitCount := 24;
bmi.bmiHeader.biPlanes := 1;
bmi.bmiHeader.biWidth := w;
bmi.bmiHeader.biHeight := h;
bmi.bmiHeader.biSizeImage := bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * 3;
bmi.bmiHeader.biClrUsed :=0;
bmi.bmiHeader.biClrImportant:=0;
MemBmp := CreateDIBSection(DC, bmi, DIB_RGB_COLORS, pBits, 0, 0);
MemDC := CreateCompatibleDC(DC);
SelectObject(MemDC, MemBmp);
BitBlt(MemDC, 0, 0, w, h, DC, 0, 0, SRCCOPY);
x := R;
LastX := R;
y := 0;
T := 0;
J:=0;
while J<=3 do
begin
KX := J mod 2*2-1;
KY := J div 2 mod 2*2-1;
SetPixel(BMI, PBits, KX*x+cx, KY*y+cy, 1, color);
SetPixel(BMI, PBits,KX*y+cx, KY*x+cy, 1, color);
Inc(J);
end;
while x>y do
begin
y := y+1;
D := Ceil(Sqrt(R*R-y*y))-Sqrt(R*R-y*y);
if D<T then
begin
x := x-1;
end;
if x<y then
begin
Break;
end;
if (x=y) and (LastX=x) then
begin
Break;
end;
J:=0;
while J<=3 do
begin
KX := J mod 2*2-1;
KY := J div 2 mod 2*2-1;
SetPixel(BMI, PBits, KX * x + cx, KY * y + cy, 1-D, color);
SetPixel(BMI, PBits, KX * y + cx, KY * x + cy, 1-D, color);
if x-1>=y then
begin
SetPixel(BMI, PBits,KX*(x-1)+cx, KY*y+cy, D, color);
SetPixel(BMI, PBits,KX*y+cx, KY*(x-1)+cy, D, color);
end;
Inc(J);
end;
T := D;
LastX := X;
end;
BitBlt(DC, 0, 0, W, H, MemDC, 0, 0, SRCCOPY);
DeleteObject(MemBmp);
DeleteObject(MemDC);
end;
-
При большом кол-ве отрисовок, особенно с наложениями, буферный битмап будет просто необходим - чтобы не мерцало. Но если так уж хочется ПРЯМО на экран - можно использовать DirectDraw с выводом на "первичку". Прямее некуда - без учёта перекрытия окон и строго в пиксельном формате рабочего стола. Сейчас сравнил: DrawWuCircle(400, 300, R, Canvas); // R300 - 18 ms, R30 - 2 ms DrawWuCircleDDraw(fd, 400, 300, R, 0); // R300 - 1 ms, R30 - 0.15 ms DrawCircle1 вообще не работает, GetScanLine возвращает nil.
-
> Sapersky (23.01.08 13:50) [42]
> DrawWuCircleDDraw(fd, 400, 300, R, 0);
А что внутри?
> DrawCircle1 вообще не работает, GetScanLine возвращает nil.
У меня работает, но там код сырой, где то ошибка(и).
-
> При большом кол-ве отрисовок, особенно с наложениями, буферный > битмап будет просто необходим - чтобы не мерцало.
Хотелось бы чтобы в функцию передавалось именно DC, как и в WinApi, но тогда буферный битмап придется создавать внутри функции, что мне не очень нравится.
-
А что внутри?
Там далеко не всё внутри, инициализация/финализация DDraw, например, снаружи. И полностью код трудно привести, используется много разных модулей. Если надо - позже выложу пример. И, конечно, передаётся в функцию совсем не DC, так что внешнего сходства с GDI (если оно имеет значение) нет. Поэтому, возможно, проще всё-таки буферный битмап на всю форму (скорость сопоставимая).
-
-
> Sapersky (23.01.08 16:55) [46]
Спасибо посмотрел. Добавил ту свою функцию со сканлайном, что выше. При маленьких размерах окружностей результаты таковы:
На основе FastDIB - 633 На основе DD - 1480 Моя функция со сканлайном - 1237
При рисовании на холсте 1280*1024:
На основе FastDIB - 3967 На основе DD - 3877 Моя функция со сканлайном - 9600
Т.е. DD не дает особого преимущества.
-
Вариант через SetPixel 10625 и 33023 соответственно.
-
Результаты буферных функций - с копированием буфера на экран или без? И если оно делается, то как - по моему методу, с заранее созданным буфером на всю форму (картинка с экрана в него не копируется), или как в [41], с созданием битмапа "на лету" и копированием туда-обратно?
Так, ради интереса. У меня получилось - с учётом копирования быстрее DD, без копирования - "неDD". Оно и понятно, функция одна и та же, отличается метод (и вообще наличие) передачи данных из/в видеопамять. Т.е. DD быстрее для единичной отрисовки - драйвер, видимо, передаёт туда-обратно относительно небольшие блоки данных, не весь экран, хотя даётся команда на блокировку всей "первички". Но если рисовать нужно много, лучше использовать буферный метод - поднакопить данные в системной памяти и потом "одним движением" сбросить в видео.
-
> Sapersky (23.01.08 18:37) [49]
В [47] и [48] копирование картинки с экрана в ваших функциях не производилось, а в моей производилось. Если в вашу фунцию с FastDIB добавить создание экземпляра TFastDIB на лету и копирование в него картинки с экрана, а потом вывод обратно на экран, то скорость будет примерно такая же как и в моей функции. Так и там и там используется одна и таже BitBlt и главные тормоза в ней. Пикселей перебирается не так уж много в алгоритме, поэтому сам алгоритм на скорость влияет мало, как и поиск строки в битмапе и точки в строке и вычисление ее цвета.
> У меня получилось - с учётом копирования быстрее DD, без > копирования - "неDD".
ну собственно у меня так же.
Но вариант с DD мне все равно не подходит. Если только для удовлетворения любопытства.
|