Как увеличить скорость отрисовки на Canvas?

I dont know
Дата: 27.02.2014 20:21:35
Приветствую, играюсь тут с канвасом, пытаюсь нарисовать на paintbox-е сетку и по ней потом вырисовывать объекты. Нарисовал сетку и добавил возможность масштабирования всего этого дела, но по субъективным ощущениям, работает это как-то не очень быстро, особенно когда коэффициент масштабирования становится минимальным(т.е точек сетки на экране макимум). Вот кусок кода, можно ли его как-то оптимизировать, правильно ли я рисую сетку, может быть что-то делаю не правильно? Кратко, у нас есть фрейм, в котором лежит paintbox и панель меню. Собственно рисование сетки находится в функции PrepareCanvas.

P.S. Пишу используя среду Lazarus под Linux, но принципиальной разницы думаю нет

+
// тут объявление формы пропущу
var
  MainForm      : TMainForm;
  PrimitiveList : TList;
  ZoomFactor    : Real;

implementation

{$R *.lfm}

{ TMainForm }

procedure TMainForm.FileMenuItemClick(Sender: TObject);
begin

end;

procedure TMainForm.ExitMenuItemClick(Sender: TObject);
begin
     Close;
end;

procedure TMainForm.FormResize(Sender: TObject);
begin

end;

procedure TMainForm.DeleteMenuItemClick(Sender: TObject);
begin

end;

procedure TMainForm.OnMouseDown(Sender : TObject; Button : TMouseButton;
Shift : TShiftState; X, Y : Integer);
var
    p : Pointer;
    rp : TPoint;
begin
     for p in PrimitiveList do begin
         if TPrimitive(p).HitTest(X, Y) = true then
            ShowMessage('Click on the Line!');
     end;
end;

procedure TMainForm.OnMouseMove(Sender : TObject; Shift : TShiftState; X,
Y : Integer);
begin

end;

procedure TMainForm.OnMouseWheel(Sender : TObject; Shift : TShiftState;
WheelDelta : Integer; MousePos : TPoint; var Handled : Boolean);
begin
     if(WheelDelta > 0) then
         ZoomIn()
     else
         ZoomOut();

     PaintBox.Refresh;
end;

procedure TMainForm.OnPaint(Sender : TObject);
var
   p : Pointer;
begin
     PrepareCanvas(true);
    // for p in PrimitiveList do begin
    //     TPrimitive(p).Draw(PaintBox.Canvas, ZoomFactor);
    // end;
end;


procedure TMainForm.OpenClick(Sender: TObject);
begin

end;


procedure TMainForm.FormCreate(Sender: TObject);
begin
     PrimitiveList := TList.Create();
     ZoomFactor := 1.0;
     ScrollBox.VertScrollBar.Range := 1000;
     ScrollBox.HorzScrollBar.Range := 1000;
end;

procedure TMainForm.DrawLineMenuItemClick(Sender: TObject);
var
   Line : TLine;
   a, b : TPoint;
begin
     a.X := 200; a.Y := 50;
     b.X := 300; b.Y := 150;
     Line := TLine.Create(a, b);
     Line.Thickness := 1;
     Line.Color := clRed;
     Line.IsSelected := true;
     PrimitiveList.Add(Line);
     PaintBox.Refresh;

end;

procedure TMainForm.ActivateForm(Sender : TObject);
begin

end;

procedure TMainForm.DrawMenuClick(Sender: TObject);
begin

end;


procedure TMainForm.PrepareCanvas(DrawGrid : Boolean);
var
    CellSize : Integer;
    i, j : Integer;
begin
    CellSize := Round(PixelsInMM * ZoomFactor);
    i := 0; j := 0;
    with PaintBox do begin
         Canvas.Brush.Color := clBlack;
         Canvas.Pen.Color := clGray;
         Canvas.Clear;


         { Draw grid if it needs }
         if DrawGrid = True then begin
             while i < ClientRect.Right do begin
                 while j < ClientRect.Bottom do begin
                     Canvas.Line(i, j, i+1, j+1);
                     j := j + CellSize;
                 end;
                 i := i + CellSize;
                 j := 0;
             end;
         end;
    end;
end;

procedure TMainForm.RotateMenuItemClick(Sender : TObject);
var
    p : Pointer;
    rp : TPoint;
begin
     for p in PrimitiveList do begin
         TPrimitive(p).Rotate(15, rp);
     end;
     PaintBox.Refresh;
end;


{ -------------- Zoom Functions -------------------- }

procedure TMainForm.ZoomIn();
begin
     if (ZoomFactor < MaxZoomFactor) then
        ZoomFactor := ZoomFactor + ZoomStep;
end;

procedure TMainForm.ZoomOut();
var
    tmp : Real;
begin
     tmp := ZoomFactor - ZoomStep;
     if (tmp > MinZoomFactor) then
        ZoomFactor := tmp;
end;

end.                                                     
fd00ch
Дата: 27.02.2014 20:25:22
не пробовал никогда быстро рисовать сетку, но не "дешевле" ли это сделать сплошной заливкой всей области, использовав для этого кастомную кисть с битмапом-сеткой в качестве основы?
fd00ch
Дата: 27.02.2014 20:26:25
ну или тупо рисовать на временном битмапе, на paintbox выводить готовый результат за 1 отрисовку
Соколинский Борис
Дата: 27.02.2014 20:39:16
I dont know
P.S. Пишу используя среду Lazarus под Linux, но принципиальной разницы думаю нет

Думаю, что есть.
В винде на нормальном компе не успеешь заметить как это отрисуется.
I dont know
Дата: 27.02.2014 20:51:23
fd00ch,

Это как? А как в этом случае масштабировать сетку при изменении масштаба? Я думал попробовать вместо вложенных циклов использовать один, т.е пройти слева на право и отрисовывать вертикальные dash line, где dash был бы как раз в размер ячейки. Но канва не умеет рисовать dash line, только если свой велосипед городить, поэтому решил не идти по этому пути, не известно ещё что получится. Ещё думал, что будет, если рисовать скажем на битмапе, а потом просто копировать это всё на канву, как в этом случае производительность будет?
I dont know
Дата: 27.02.2014 20:53:03
Соколинский Борис,

Так у меня и тут комп не плохой, 4-х ядерный, 4 гига оперативы... Если у кого есть lazarus установленный, могу выложить код проекта, попробуете у себя. Хотя оно может и под делфи заведется )
fd00ch
Дата: 27.02.2014 21:22:33
I dont know
А как в этом случае масштабировать сетку при изменении масштаба?
создать новый битмап для кисти

I dont know
как в этом случае производительность будет?
пробуй)) вкратце - выше. вообще говоря, в другом режиме использовать paintbox я не вижу смысла
I dont know
Дата: 27.02.2014 21:59:11
fd00ch,

Хочу попробовать с OpenGLContext, но не могу толком найти доки, как его использовать :(
Соколинский Борис
Дата: 28.02.2014 01:06:06
I dont know
Соколинский Борис,

Так у меня и тут комп не плохой, 4-х ядерный, 4 гига оперативы... Если у кого есть lazarus установленный, могу выложить код проекта, попробуете у себя. Хотя оно может и под делфи заведется )

Оперативка тут вообще не нужна. Для форсирования векторной отрисовки может графический ускоритель использоваться, но для этого нужно чтобы у него нормальные драйвера стояли, а с этим в пингвине традиционно беда.
Warstone
Дата: 03.03.2014 03:48:20
А BeginPaint / EndPaint пробовали?