Конференция "Media" » Вывести графику на Canvas с Anti-Aliasing'ом [D7, WinXP]
 
  • DVM © (22.01.08 23:05) [40]
    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;

  • DVM © (22.01.08 23:06) [41]
    А вот то же самое (черновой вариант) со сканлайнами


    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;


  • Sapersky (23.01.08 13:50) [42]
    При большом кол-ве отрисовок, особенно с наложениями, буферный битмап будет просто необходим - чтобы не мерцало.
    Но если так уж хочется ПРЯМО на экран - можно использовать 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.
  • DVM © (23.01.08 13:56) [43]

    > Sapersky   (23.01.08 13:50) [42]


    > DrawWuCircleDDraw(fd, 400, 300, R, 0);

    А что внутри?


    > DrawCircle1 вообще не работает, GetScanLine возвращает nil.

    У меня работает, но там код сырой, где то ошибка(и).
  • DVM © (23.01.08 14:05) [44]

    > При большом кол-ве отрисовок, особенно с наложениями, буферный
    > битмап будет просто необходим - чтобы не мерцало.

    Хотелось бы чтобы в функцию передавалось именно DC, как и в WinApi, но тогда буферный битмап придется создавать внутри функции, что мне не очень нравится.
  • Sapersky (23.01.08 15:09) [45]
    А что внутри?

    Там далеко не всё внутри, инициализация/финализация DDraw, например, снаружи. И полностью код трудно привести, используется много разных модулей. Если надо - позже выложу пример.
    И, конечно, передаётся в функцию совсем не DC, так что внешнего сходства с GDI (если оно имеет значение) нет. Поэтому, возможно, проще всё-таки буферный битмап на всю форму (скорость сопоставимая).
  • Sapersky (23.01.08 16:55) [46]
    http://sapersky.narod.ru/files/DrawEllipse.rar
    Глубина цвета рабочего стола должна быть 32 bpp.
  • DVM © (23.01.08 17:19) [47]

    > Sapersky   (23.01.08 16:55) [46]

    Спасибо посмотрел. Добавил ту свою функцию со сканлайном, что выше.
    При маленьких размерах окружностей результаты таковы:

    На основе FastDIB  - 633
    На основе DD  - 1480
    Моя функция со сканлайном   - 1237

    При рисовании на холсте 1280*1024:

    На основе FastDIB  - 3967
    На основе DD  - 3877
    Моя функция со сканлайном   - 9600

    Т.е. DD не дает особого преимущества.
  • DVM © (23.01.08 17:23) [48]
    Вариант через SetPixel 10625 и 33023 соответственно.
  • Sapersky (23.01.08 18:37) [49]
    Результаты буферных функций - с копированием буфера на экран или без? И если оно делается, то как - по моему методу, с заранее созданным буфером на всю форму (картинка с экрана в него не копируется), или как в [41], с созданием битмапа "на лету" и копированием туда-обратно?

    Так, ради интереса. У меня получилось - с учётом копирования быстрее DD, без копирования - "неDD". Оно и понятно, функция одна и та же, отличается метод (и вообще наличие) передачи данных из/в видеопамять.
    Т.е. DD быстрее для единичной отрисовки - драйвер, видимо, передаёт туда-обратно относительно небольшие блоки данных, не весь экран, хотя даётся команда на блокировку всей "первички". Но если рисовать нужно много, лучше использовать буферный метод - поднакопить данные в системной памяти и потом "одним движением" сбросить в видео.
  • DVM © (24.01.08 11:22) [50]

    > Sapersky   (23.01.08 18:37) [49]

    В [47] и [48] копирование картинки с экрана в ваших функциях не производилось, а в моей производилось. Если в вашу фунцию с FastDIB добавить создание экземпляра TFastDIB на лету и копирование в него картинки с экрана, а потом вывод обратно на экран, то скорость будет примерно такая же как и в моей функции. Так и там и там используется одна и таже BitBlt и главные тормоза в ней. Пикселей перебирается не так уж много в алгоритме, поэтому сам алгоритм на скорость влияет мало, как и поиск строки в битмапе и точки в строке и вычисление ее цвета.


    > У меня получилось - с учётом копирования быстрее DD, без
    > копирования - "неDD".

    ну собственно у меня так же.

    Но вариант с DD мне все равно не подходит. Если только для удовлетворения любопытства.
 
Конференция "Media" » Вывести графику на Canvas с Anti-Aliasing'ом [D7, WinXP]
Есть новые Нет новых   [134431   +15][b:0][p:0.005]