Конференция "Media" » Вывести графику на Canvas с Anti-Aliasing'ом [D7, WinXP]
 
  • hypnotize (10.03.07 11:45) [0]
    Здратвуйте Мастера! Не знает ли кто-нибудь из присутвующих как выводить на Канву графику (с Трансперентом) со сглаживанием (Анти-Алиасингом)? То есть нету ли какого либо аналога процедуры
    Canvas.Draw(x,y,graphic);

    только, со сглаживанием)
  • Ricks © (10.03.07 12:09) [1]
    Аналога нет, и уточни что тебе надо рисовать? Картинку или примитивы?
  • GrayFace © (10.03.07 12:13) [2]
    Разве картинку возможно выводить с антиальясингом? По сабжу ничего не скажу, погугли, для С++ имеется библиотека с такими штуками.
  • Ricks © (10.03.07 12:32) [3]
    Может нужна 32-х битная картинка?
    Тогда смотри AlphaBlend или пиши свою процедуру!
  • hypnotize (10.03.07 12:41) [4]
    Выводить нужно Bitmap с
    Transperent:=true;

    (невидимая часть фиолетовым цветом закрашена) , но после вывода очень заметны грани, нельзя ли их сгладить как нить? Дело в том что я сам не понимаю принцип работы Анти Алиасинга, я нашел в инете один примерчик, но он жуууутко тормозит.
    А как отрисовать картинку с AlphaBlend'ом?
  • oxffff © (10.03.07 13:20) [5]
    Тебе поможет GDI+.

    Здесь порт на delphi
         {******************************************************************}
         { GDI+ API                                                         }
         {                                                                  }
         { home page : http://www.progdigy.com                              }
         { email     : hgourvest@progdigy.com                               }
         {                                                                  }
         { date      : 15-02-2002                                           }
         {                                                                  }
         { The contents of this file are used with permission, subject to   }
         { the Mozilla Public License Version 1.1 (the "License"); you may  }
         { not use this file except in compliance with the License. You may }
         { obtain a copy of the License at                                  }
         { http://www.mozilla.org/MPL/MPL-1.1.html                          }
         {                                                                  }
         { Software distributed under the License is distributed on an      }
         { "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   }
         { implied. See the License for the specific language governing     }
         { rights and limitations under the License.                        }
         {                                                                  }
         { *****************************************************************}
  • oxffff © (10.03.07 13:23) [6]
    Есть eще GDI функции BitBlt,MaskBlt,StretchBlt.
  • oxffff © (10.03.07 13:27) [7]
    Если тебе нужен Анти-Алиасинг тогда используй GDI+

    SetCompositingMode Method у TGPGraphic

    CompositingModeSourceOver
    Specifies that when a color is rendered, it is blended with the background color. The blend is determined by the alpha component of the color being rendered.

    CompositingModeSourceCopy
    Specifies that when a color is rendered, it overwrites the background color. This mode cannot be used along with TextRenderingHintClearTypeGridFit.

    Graphics::SetInterpolationMode Method у TGPGraphic

    Constants

    InterpolationModeInvalid
    Used internally

    InterpolationModeDefault
    Specifies the default interpolation mode.

    InterpolationModeLowQuality
    Specifies a low-quality mode.

    InterpolationModeHighQuality
    Specifies a high-quality mode.

    InterpolationModeBilinear
    Specifies bilinear interpolation. No prefiltering is done. This mode is not suitable for shrinking an image below 50 percent of its original size.

    InterpolationModeBicubic
    Specifies bicubic interpolation. No prefiltering is done. This mode is not suitable for shrinking an image below 25 percent of its original size.

    InterpolationModeNearestNeighbor
    Specifies nearest-neighbor interpolation.

    InterpolationModeHighQualityBilinear
    Specifies high-quality, bilinear interpolation. Prefiltering is performed to ensure high-quality shrinking.

    InterpolationModeHighQualityBicubic
    Specifies high-quality, bicubic interpolation. Prefiltering is performed to ensure high-quality shrinking. This mode produces the highest quality transformed images.

    Вот и все.
  • oxffff © (10.03.07 13:35) [8]
    Анти-Алиас здесь
    Graphics::SetSmoothingMode Method

    The SmoothingMode enumeration specifies the type of smoothing (antialiasing) that is applied to lines and curves. This enumeration is used by the GetSmoothingMode and SetSmoothingMode methods of the Graphics class.

    Syntax

    typedef enum {
       SmoothingModeInvalid = QualityModeInvalid,
       SmoothingModeDefault = QualityModeDefault,
       SmoothingModeHighSpeed = QualityModeLow,
       SmoothingModeHighQuality = QualityModeHigh,
       SmoothingModeNone,
       SmoothingModeAntiAlias8x4,
       SmoothingModeAntiAlias = SmoothingModeAntiAlias8x4,
       SmoothingModeAntiAlias8x8
    } SmoothingMode;

    Constants

    SmoothingModeInvalid
    Reserved.

    SmoothingModeDefault
    Specifies that smoothing is not applied.

    SmoothingModeHighSpeed
    Specifies that smoothing is not applied.

    SmoothingModeHighQuality
    Specifies that smoothing is applied using an 8 X 4 box filter.

    SmoothingModeNone
    Specifies that smoothing is not applied.

    SmoothingModeAntiAlias8x4
    Specifies that smoothing is applied using an 8 X 4 box filter.

    SmoothingModeAntiAlias
    Specifies that smoothing is applied using an 8 X 4 box filter.

    SmoothingModeAntiAlias8x8
    Specifies that smoothing is applied using an 8 X 8 box filter.
  • hypnotize (10.03.07 13:43) [9]
    Ы, как много информации, буду изучать)
  • hypnotize (10.03.07 13:43) [10]
    Ы, как много информации, буду изучать) спасибо
  • hypnotize (10.03.07 13:43) [11]
    Ы, как много информации, буду изучать) спасибо
  • Степан (11.03.07 22:11) [12]
    Ы... а может ненадо... GDI рулит!
  • Степан (11.03.07 22:16) [13]

    function DrawAlphaBitmap(const Canvas: TCanvas; var ColorBitmap,
     MaskBitmap: TBitmap; X, Y: Integer): Boolean;

    type
     TArray = array [0..0] of Integer;

     function GetGradientColor(Color1, Color2: TColor; BlockCount, BlockIndex:
       Integer): TColor;
     var
       DifR, DifB, DifG: Integer;
       SR, SG, SB: Integer;
     begin
       SR := Color1 and $FF;
       DifR := (Color2 and $FF) - SR;
       SG := (Color1 shr 8) and $FF;
       DifG := ((Color2 shr 8) and $FF) - SG;
       SB := (Color1 shr 16) and $FF;
       DifB:=((Color2 shr 16) and $FF) - SB;
       Result := RGB((BlockIndex * DifR) div (BlockCount - 1) + SR,
         (BlockIndex * DifG) div (BlockCount - 1) + SG,
         (BlockIndex * DifB) div (BlockCount - 1) + SB);
     end;

     function GetBitsColor(var Bits: Pointer; Width, Height: Integer;
     X, Y: Cardinal): Integer;
     begin
       Result := 0;
       try
         Result := TArray(Bits^)[Integer(X) + Integer(Y) * Width];
       except
       end;
     end;

     procedure SetBitsColor(var Bits: Pointer; Width, Height: Integer;
       X, Y: Cardinal; Color: Integer);
     begin
       try
         TArray(Bits^)[Integer(X) + Integer(Y) * Width] := Color;
       except
       end;
     end;

     function GetMaxIntensity(Color: TColor): Byte;
     var
       SR, SG, SB: Byte;
     begin
       SR := Color and $FF;
       SG := (Color shr 8) and $FF;
       SB := (Color shr 16) and $FF;
       if SR > SG then
         Result := SR
       else
         Result := SG;
       if SB > Result then
         Result := SB;
     end;

    var
     ColorBits: Pointer;
     MaskBits: Pointer;
     DestBitmap: HBITMAP;
     DestDC: HDC;
     DestBits: Pointer;
     BitmapInfo: TBitmapInfo;
     Color1, Color2, MaskColor: Integer;
     CX, CY: Integer;
    begin
     Result := False;
     if (MaskBitmap.Width < ColorBitmap.Width) or (MaskBitmap.Width <
     ColorBitmap.Width) then
       Exit;
     GetMem(ColorBits, ColorBitmap.Width * ColorBitmap.Height *
       GetDeviceCaps(ColorBitmap.Canvas.Handle, BITSPIXEL) div 8);
     BitmapInfo.bmiHeader.biSize := SizeOf(TBitmapInfoHeader);
     BitmapInfo.bmiHeader.biWidth := ColorBitmap.Width;
     BitmapInfo.bmiHeader.biHeight := - ColorBitmap.Height;
     BitmapInfo.bmiHeader.biPlanes := 1;
     BitmapInfo.bmiHeader.biBitCount := GetDeviceCaps(ColorBitmap.Canvas.Handle,
       BITSPIXEL);
     BitmapInfo.bmiHeader.biCompression := BI_RGB;
     if GetDIBits(ColorBitmap.Canvas.Handle, ColorBitmap.Handle, 0,
     ColorBitmap.Height, ColorBits, BitmapInfo, DIB_RGB_COLORS) = 0 then
       Exit;
     GetMem(MaskBits, MaskBitmap.Width * MaskBitmap.Height *
       GetDeviceCaps(MaskBitmap.Canvas.Handle, BITSPIXEL) div 8);
     BitmapInfo.bmiHeader.biSize := SizeOf(TBitmapInfoHeader);
     BitmapInfo.bmiHeader.biWidth := MaskBitmap.Width;
     BitmapInfo.bmiHeader.biHeight := - MaskBitmap.Height;
     BitmapInfo.bmiHeader.biPlanes := 1;
     BitmapInfo.bmiHeader.biBitCount := GetDeviceCaps(MaskBitmap.Canvas.Handle,
       BITSPIXEL);
     BitmapInfo.bmiHeader.biCompression := BI_RGB;
     if GetDIBits(MaskBitmap.Canvas.Handle, MaskBitmap.Handle, 0,
       MaskBitmap.Height, MaskBits, BitmapInfo, DIB_RGB_COLORS) = 0 then
       Exit;
     BitmapInfo.bmiHeader.biSize := SizeOf(TBitmapInfoHeader);
     BitmapInfo.bmiHeader.biWidth := ColorBitmap.Width;
     BitmapInfo.bmiHeader.biHeight := - ColorBitmap.Height;
     BitmapInfo.bmiHeader.biPlanes := 1;
     BitmapInfo.bmiHeader.biBitCount := 32;
     BitmapInfo.bmiHeader.biCompression := BI_RGB;
     DestBitmap := CreateDIBSection(DIB_PAL_COLORS, BitmapInfo, DIB_RGB_COLORS,
       DestBits, 0, 0);
     DestDC := CreateCompatibleDC(Canvas.Handle);
     SelectObject(DestDC, DestBitmap);
     BitBlt(DestDC, 0, 0, ColorBitmap.Width, ColorBitmap.Height, Canvas.Handle, X,
       Y, SRCCOPY);

     for CY := 0 to ColorBitmap.Height - 1 do
       for CX := 0 to ColorBitmap.Width - 1 do begin
         Color1 := GetBitsColor(DestBits, ColorBitmap.Width, ColorBitmap.Height,
           CX, CY);
         Color2 := GetBitsColor(ColorBits, ColorBitmap.Width, ColorBitmap.Height,
           CX, CY);
         MaskColor := GetBitsColor(MaskBits, MaskBitmap.Width, MaskBitmap.Height,
           CX, CY);
         Color1 := GetGradientColor(Color1, Color2, 256, GetMaxIntensity(MaskColor));
         SetBitsColor(DestBits, ColorBitmap.Width, ColorBitmap.Height, CX, CY,
           Color1);
       end;
     BitBlt(Canvas.Handle, X, Y, ColorBitmap.Width, ColorBitmap.Height, DestDC, 0,
       0, SRCCOPY);

     DeleteObject(DestBitmap);
     DeleteObject(DestDC);
     Dispose(ColorBits);
     Dispose(MaskBits);
     Result := True;
    end;



    Работает неплохо для небольших изображений :)
  • oxffff © (11.03.07 23:55) [14]

    > Ы... а может ненадо... GDI рулит!


    Ы, а Анти-Алиасинг где?
  • antonn © (12.03.07 00:22) [15]
    Через GDI можно и антиалиасинг, и альфаблендинг.
    архивчик (471Кб, сорри, там просто картинка на форме:)) - http://antonn.ru/index.php?download=5b27b304_1173648104.rar&id=e08a9dc9592d84ccbcf9b87cb4f6b0f0
    скринчик (16Кб) - http://antonn.ru/index.php?download=e8970bc8_1173648034.PNG&id=c4df3b8638bca0989914c5220e90c72a
  • antonn © (12.03.07 00:48) [16]
    в посте выше алиасинг:)
  • homm © (12.03.07 08:47) [17]
    > [15] antonn ©   (12.03.07 00:22)

    Судя по скриншоту там ресамплинг по квадрату 3х3. Я как-то пытался написать алгоритм алиасинга для элипса без ресамплинга, чисто из геометрических соображений :) По моему это должно быть более эффективно, но увы, так ничего и не получилось.
  • antonn © (12.03.07 09:02) [18]
    угу, 3*3, можно и больше присобачить, если догадаться как:)
  • oxffff © (12.03.07 10:20) [19]

    > угу, 3*3, можно и больше присобачить, если догадаться как:
    > )


    Может все таки GDI+?
  • antonn © (12.03.07 21:35) [20]

    > Может все таки GDI+?
    </>
    может, автор ведь не уточнил, для каких задач ему нужно (ему вообще, имхо, альфаблендинг нужен:)), иногда можно обойтись и GDI...
  • Vovan #3 (12.03.07 23:03) [21]
    >Я как-то пытался написать алгоритм алиасинга для элипса без ресамплинга, чисто из геометрических соображений :)

    Который алгоритм Wu уже давно реализован.
  • homm © (12.03.07 23:51) [22]
    > Который алгоритм Wu уже давно реализован.
    Спасибо, нашел, буду думать как его переделать для толщины линии >1
  • ZEF © (22.01.08 00:25) [23]
    Без GDI+ можно. Смотри http://sourceforge.net/projects/graphics32
  • DVM © (22.01.08 15:19) [24]

    > homm ©   (12.03.07 08:47) [17]
    > > [15] antonn ©   (12.03.07 00:22)
    >
    > Судя по скриншоту там ресамплинг по квадрату 3х3. Я как-
    > то пытался написать алгоритм алиасинга для элипса без ресамплинга,
    >  чисто из геометрических соображений :) По моему это должно
    > быть более эффективно, но увы, так ничего и не получилось.
    >

    По поводу антиалиазинга хотел посоветоваться, раз уж пост всплыл. Каков бы не был алгоритм рисования того же эллипса с антиалиазингом есть проблема вот какого рода.

    Допустим нам надо сделать функцию, аналогичную функции GDI но с анталиазингом: Ellipse(DC, x1, y1, x2, y2). Как бы мы не рисовали точки, нам один фиг не пройти либо Set/GetPixel, что довольно медленно, либо надо созавать временный битмап, копировать на него точки, пробегать сканлайном по нему менять цвета точке в соответствии с алгоритмом рисования и далее битмап выводить обратно на DC. При маленьких размерах эллипса это быстрее, чем SetPixel, но при больших даже медленнее.
    Вот если бы как то можно было бы добраться до отдельных пикселей DC напрямую. Как вообще работают стандартные функции рисования Windows. Они явно не пользуются для изменения цвета точки функциями SetPixel.
    Нет ли каких идей?
  • antonn (work) (22.01.08 19:30) [25]
    имхо только set/getpixels для канвы...
    вот поэтому я предпочитаю все рисовать на буферном битмапе, битмап он более "физический", чем указатель-hdc, по нему можно циклом на асме пройтись и добраться до пикселей даже быстрее сканлайна.
  • DVM © (22.01.08 21:05) [26]

    > вот поэтому я предпочитаю все рисовать на буферном битмапе,
    >  битмап он более "физический", чем указатель-hdc, по нему
    > можно циклом на асме пройтись и добраться до пикселей даже
    > быстрее сканлайна.

    Сканлайном я лишь метод обозначил. На асме или нет, но при больших размерах этот метод медленнее, чем то же самое, но через SetPixel.
  • homm © (22.01.08 21:55) [27]
    > [24] DVM ©   (22.01.08 15:19)
    > При маленьких размерах эллипса это быстрее, чем SetPixel,
    > но при больших даже медленнее.

    Напрасно ты так думаешь. Размер тут не причем.
  • DVM © (22.01.08 22:18) [28]

    > Напрасно ты так думаешь.

    Я не думаю, я попробовал. Блиттинг с канвы и обратно при большом размере картинки занимает больше времени, чем отрисовка всех точек эллипса. через SetPixel.

    Пример: окружность радиус 100
    через SetPixel - 16800 микросекунд
    через Scanline - 3400 микросекнд

    Пример: окружность радиус 500
    через SetPixel - 35000 микросекунд
    через Scanline - 20000 микросекнд

    Пример: окружность радиус 700
    через SetPixel - 32000 микросекунд
    через Scanline - 29000 микросекнд

    Для роадиуса 1000 сканлайн уже отстает
  • homm © (22.01.08 22:21) [29]
    Функции GDI уже давно во всю используют аппаратное ускорение. Проблема с DC даже не в том, что он менее «физический», просто объект, для работы с которым DC является идентификатаром, находится в виделпамяти (при наличии доступной оной).

    Но при расчете эллипса вывод это дело 10-е, важнее математика. У меня есть алгоритм идеально сглаженного заполненного эллипса. У меня есть алгоритм получения (что проще) идеальной окружности с произвольной толшиной линии. Но я нигде не видел алгоритма получения идельного матиматически сглаженного эллипса с произвольной толщиной линии. Все виденые мной способы получения такого сглаживания не математическим путем основывались на 2-х алгоритмах: Так называемый AA (рисование при большем разрешении и потом билинейная фильрация к исходному разрешению), и рисование сглаженными отрезками. Я раньше пользовался первым методом. Фотошоп по все видимости тоже пользуется им, но с некоторой оптимизацией, участки, сглаживание которых не нужно, не попадают под фильтрацию. Как я понял, в GDI+ и agg используется второй.

    Здесь сравнительный скриншот разных моих изысков в этй области и фотошопа:
    http://homm86.narod.ru/files/myellipse-new.png

    PS. БОЛЬШОЕ спасибо DM, в котором по видимому есть автосейв сообщений, без него это сообщение стало бы намного короче.
  • DVM © (22.01.08 22:28) [30]

    > Но при расчете эллипса вывод это дело 10-е, важнее математика.
    >  

    Математика для меня не проблема, здесь я хоть могу крутить - вертеть - придумывать. А вот сделать быстрее вывод похоже невозможно.

    Алгоритмы то все у меня есть, кроме пожалуй сглаженного эллипса с произвольной толщиной линии и заливкой. Но впринципе в книгах описан - сделать можно будет.
  • homm © (22.01.08 22:34) [31]
    > [30] DVM ©   (22.01.08 22:28)
    > Но впринципе в книгах описан - сделать можно будет.

    Проверь, математические ли там алгоритмы, а не то, что я описал?
  • DVM © (22.01.08 22:35) [32]

    > homm ©  

    да стандартный метод Wu, основанный на вычислении площади трапеции.

    вот результат кстати

    http://dvmuratov.narod.ru/aa.png
  • homm © (22.01.08 22:41) [33]
    > [32] DVM ©   (22.01.08 22:35)
    > да стандартный метод Wu, основанный на вычислении площади
    > трапеции.
    >
    > вот результат кстати
    >
    > http://dvmuratov.narod.ru/aa.png

    До такого, как я уже сказал, я и сам дошел :) Ты кажется говорил об алгоритме с произвольной толщиной линии.
  • DVM © (22.01.08 22:43) [34]

    > Ты кажется говорил об алгоритме с произвольной толщиной
    > линии.

    Я же наоборот говорил, что кроме него все есть.
  • DVM © (22.01.08 22:44) [35]

    > homm ©

    Слушай, а может рисовать вложенные эллипсы, а между ними пространство залить?
  • DVM © (22.01.08 22:50) [36]
    Хотя не, не вложатся они нормально один в другой. Чем больше сплющен эллипс, тем более различаться по толщине будет граница.
  • homm © (22.01.08 22:56) [37]
    > [35] DVM ©   (22.01.08 22:44)
    > Слушай, а может рисовать вложенные эллипсы, а между ними
    > пространство залить?

    Наивный :)


    > [36] DVM ©   (22.01.08 22:50)

    Угу.
  • homm © (22.01.08 22:59) [38]
    > [28] DVM ©   (22.01.08 22:18)
    > Я не думаю, я попробовал.

    Ну вот я попробовал:
    procedure TForm1.Button2Click(Sender: PObj);
    var
     BMP: PBitmap;
     I, T, J, K: Integer;
     DC: HDC;
     C: PCanvas;
    begin
     T := GetTickCount;
     DC := GetDC(0);
     for i := 0 to 49 do begin
       BMP := NewDIBBitmap(1280, 1024, pf32bit);
       BitBlt(BMP.Canvas.Handle, 0, 0, 1280, 1024, DC, 0, 0, SRCCOPY);
       FillMemory(BMP.DIBBits, 1280*1024*4, $80);
       BMP.Draw(DC, 0, 0);
       BMP.Free;
     end;
     ReleaseDC(0, DC);
     InvalidateRect(0, nil, false);
     ShowMessage(int2str(gettickCount-T));

     T := GetTickCount;
     DC := GetDC(0);
     C := NewCanvas(DC);
     for i := 0 to 0 do begin
       for j := 0 to 1024-1 do
         for k := 0 to 1280-1 do begin
           C.Pixels[K,J] := $80808080;
         end;
     end;
     ReleaseDC(0, DC);
     C.Free;
     InvalidateRect(0, nil, false);
     ShowMessage(int2str(gettickCount-T));
    end;



    Вариант1: 547 мс
    Вариант2: 842 мс
    А теперь обрати внимание, что первый вариант выполняется в цикле 50 раз, а второй только 1 :) Разница примерно в 80 раз. Уж не знаю, как ты так мерил.
  • DVM © (22.01.08 23:01) [39]

    > homm ©

    Ты не забывай, что алгоритм Wu не перебирает все пикселы прямоугольника, в который вписан в эллипс. Берется сравнительно небольшое число точек. Твой пример не подходит совсем.
  • 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]
Есть новые Нет новых   [133928   +472][b:0.001][p:0.009]