Конференция "Игры" » Быстрый канвас [Delphi, Windows, ХР]
 
  • Pa5ha © (05.08.07 18:53) [0]
    Хотя пишу я и не игру, но вопрос, наверно, должен быть именно здесь :)
    Вобщем пишу прогу для построения принципиальных схем. Движог для построений готов. Т.е. можно рисовать линии, круги, добавлять надписи, выделять по разному. Но проблема в том, что это все жутко тормозит при большом кол-ве палок на схеме. Надо бы это как-то оптимизировать. Собственно вопрос получается такой широкий. Расскажите как это делать плз ) Какие способы есть быстро нарисовать (опенГЛ врубать туда не хотелось бы)?

    На данный момент есть несколько конкретных вопросов.
    1. При рисовании новой линии (когда она тянеца за курсором), при выделении чего-либо на экране прямоугольником, при перетаскивании разных объектов я делаю так: копирую содержимое экрана в tbitmap (кстати, все делаю в компоненте image), потом на нем рисую прямоугольник выделения или линию, тянущуюся за курсором или надпись, при изменении картинки из tbitmap-a все сую в имэдж и опять рисую новый ещё не поставленный объект. Это, наверно, не очень правильно :) Просто мне кажеца что моя прога немного подтормаживает. Вот гадаю как сделаны остальные проги.
    2. Текст. Обычный текст рисовать Текстаутом - элементарно. Но вот мне надо бы текст рисовать повернутым на 90, 180 и 270 градусов. Спобосы с созданием повернутых шрифтов мне не очень понравились, поэтому я сначала рисую текст ещё один тбитмап, потом попиксельно поворачиваю, потом рисую с прозрачностью там где надо. Но это совсем исзращенный способ и тупит опять же сильно даже при маленьких надписях. Как можно сделать по нормальному? :)
  • Pa5ha © (05.08.07 18:54) [1]
    Просто помница, кто-то писал игры на гди и они достаточно шустро работали.
  • antonn © (05.08.07 20:57) [2]
    1. Делать так. Создать буферный битмап, на него рисуются уже "абсолютно" нарисованные объекты, т.е. которые не тянуться одним концом за курсором:) Нужный кусок этого буферного битапа выводить в TPaintbox ( canvas.copyrect() достаточно быстро работает ). Пока объект бегает за курсором, выводить его после битмапа на канву TPaintbox. Как только объект "готов к нанесению", копировать его на этот буферный битмап. Очень непонятно это - " копирую содержимое экрана в tbitmap", а потом убивает "кстати, все делаю в компоненте image" :)
    2. Попиксельно видимо используется canvas.pixels[] - будет медлено:) с использованием scanline на порядок быстрее (ну если не на порядок, то раз в 5-6 точно). Но вроде кто то приводил код трансформации шрифта для наклонных надписей, может сюда заглянет%)

    я бы вообще предпочел наботать не с канвасом, а с битмапов - канвас это нечто неосязаемое, а пиксели у битмапа очень даже осязаемы:) но это так, имхо:)
  • @!!ex © (05.08.07 21:02) [3]
    А зачем TPaintBox?
    Почем тупо на форму BitBlt не делать? Самая быстрая операция вывода...
  • Sdubaruhnul (05.08.07 21:21) [4]
    >А зачем TPaintBox?
    Почем тупо на форму BitBlt не делать? Самая быстрая операция вывода...


    Тупо BitBlt на TPaintBox.
  • antonn © (05.08.07 21:27) [5]

    > @!!ex ©   (05.08.07 21:02) [3]

    ну читая пост автора пикинул, что у него тупо есть еще кнопочки всякие, может панели плавающие, т.ч. лучше пантбокс:)
  • @!!ex © (05.08.07 22:15) [6]
    > Тупо BitBlt на TPaintBox.

    Лишний контрол скорости не прибавит.


    > ну читая пост автора пикинул, что у него тупо есть еще кнопочки
    > всякие, может панели плавающие, т.ч. лучше пантбокс:)

    Ну тебе виднее... Я с канвасом таких серьезных вещей не крутил. :)
  • {RASkov} © (06.08.07 00:11) [7]
    > [0] Pa5ha ©   (05.08.07 18:53)
    > Спобосы с созданием повернутых шрифтов мне не очень понравились

    TLogFont туда вошел?
  • Pa5ha © (06.08.07 01:01) [8]
    procedure draw;
    var
    text : string;
    sz : TSize;
    hFont : THandle;
    hOld : THandle;
    begin
    SetBkMode( Canvas.Handle, TRANSPARENT );

    text := 'Horizontal Text';
    GetTextExtentPoint32( Canvas.Handle, PChar(text), Length(text), sz );
    Rectangle( Canvas.Handle, 10, 10, 10+sz.cx, 10+sz.cy );
    TextOut( Canvas.Handle, 10, 10, PChar(text), Length(text) );

    text := 'Vertical text';
    hFont := CreateFont( 0, 0, 900, 0, FW_NORMAL, 0, 0, 0,
    ANSI_CHARSET,
    OUT_DEFAULT_PRECIS,
    CLIP_DEFAULT_PRECIS,
    DEFAULT_QUALITY,
    DEFAULT_PITCH or FF_SWISS,
    nil );
    hOld := SelectObject( Canvas.Handle, hFont );
    GetTextExtentPoint32( Canvas.Handle, PChar(text), Length(text), sz );
    Rectangle( Canvas.Handle, 10, 30, 10+sz.cy, 30+sz.cx );
    TextOut( Canvas.Handle, 10, 30+sz.cx, PChar(text), Length(text) );

    SelectObject( canvas.Handle, hOld );
    DeleteObject( hFont );
    end;


    вот собсна код. Только не очень чота мне нравица. Да и некрасивый текстп олучаеца.
    > TLogFont туда вошел?

    вот можно отсюда поподробнее? :)

    По сканлайну читал какие-то справки, но или я тупой или... Как оно работает?

    А работает у меня все примерно так: на форме есть image, в котором собсна и находица вся рисуемая схема. При всяких манипуляциях с выделениями и перетаскиваниями изображение копируется в tbitmap и потом перед рисованием "плавающего" изображения полностью выводится в имейдж. Как бы особых проблем в быстродействии на небольшом экране нету, это не самое узкое место на данный момент. Но все же остальные проги вроде чуть шустрее, даже если обновляется весь экран.
    Активно пользую "он маус мув/ап/даун" имаги, в муве перерисовываю изображение, если надо.

    Чо такое кстати BitBlt? Что ему дается в качестве параметров и вообще это из какой темы? Думаю, почитать про это лишним не будет )
  • antonn © (06.08.07 01:39) [9]

    > @!!ex ©   (05.08.07 22:15) [6]

    да я не про серьезность:)
    просто или рисовать на tpaintbox, который можно поместить в любом месте формы, или даже на панельке какой нить, или мудрить с координатами и выводить на форме, а если на форме какие компоненты - так вообще капец будет.
  • {RASkov} © (06.08.07 01:57) [10]
    > [8] Pa5ha ©   (06.08.07 01:01)
    > > TLogFont туда вошел?
    >
    > вот можно отсюда поподробнее

    var
     MainForm: TMainForm;
     HFont:  THandle;
    ........
    function CreateLogFont: TLogFont;
    begin
     FillChar(Result, SizeOf(Result), 0);
     with Result, MainForm do begin
      lfHeight         := 50;
      lfWidth          := 15;
      lfWeight         := slWeight.Value;
      lfEscapement     := slEscapement.Value;
      lfOrientation    := slOrientation.Value;
      lfItalic         := ORD(cbItalic.Checked);
      lfUnderline      := ORD(cbUnderline.Checked);
      lfStrikeOut      := ORD(cbStrikeOut.Checked);
      lfCharSet        := GetMyCharSet;
      lfOutPrecision   := cmbOutPrecision.ItemIndex;
      lfClipPrecision  := 4;
      lfQuality        := cmbQuality.ItemIndex;
      lfPitchAndFamily := Byte(cmbFamily.Items.Objects[cmbFamily.ItemIndex]);
      if CheckBox1.Checked then StrPCopy(lfFaceName, FontComboBox1.FontName);
     end;
    end;

    procedure PaintText(const Cnv: TCanvas; R: TRect; S: String='^TEST_(Ё)_TEXT^');
    var LFont: TLogFont;
    begin
     if Trim(S)='' then S:='^TEST_(Ё)_TEXT^';
     LFont:=CreateLogFont;
     LFont.lfHeight := R.Bottom-R.Top;                 if LFont.lfHeight = 0 then LFont.lfHeight:=1;
     LFont.lfWidth  := (R.Right-R.Left) div Length(S); if LFont.lfWidth  = 0 then LFont.lfWidth :=1;
     HFont:=CreateFontIndirect(LFont);
     SelectObject(Cnv.Handle, HFont);
     SetTextColor(Cnv.Handle, clRed);
     SetBKmode(Cnv.Handle, TRANSPARENT);
     case MainForm.RadioGroup1.ItemIndex of
      0: DrawText(Cnv.Handle, PChar(S), -1, R, DT_LEFT);
      1: TextOut(Cnv.Handle, R.Left, R.Top, PChar(S), Length(S));
     end;
     DeleteObject(HFont);
    end;


    Это из моего тестового проекта, где я пытаюсь с помощью TLogFont'а "рисовать" текст в определенном прямоугольнике, но что-то криво оно работает, но для твоих целей вполне может сгодится.... т.е. убери параметр R из PaintText, высоту шрифта (в CreateLogFont) задай в lfHeight, а ширину символа (lfWidth) делай 0 (будет использоваться дефолтное значение)....
  • {RASkov} © (06.08.07 02:09) [11]
    Впрочем [10] тоже самое почти, что и в [8]... не обращай на [10] внимания....
  • имя (06.08.07 09:40) [12]
    Удалено модератором
  • Pa5ha © (10.08.07 03:07) [13]
    Так, я ещё раз задался вопросом. В пример хочу привести прогу Sprint-Layout. В ней при достаточно большой зарисованности холста все равно холст быстро скролица и перерисовываеца. Только что дописал ресайз в своей проге и растянул на весь стол. Огорчился. Надо исправлять.
  • Pavia © (10.08.07 04:26) [14]
    Pa5ha, задовай конкретные вопросы будут конкретные ответы. Могу сказать одно меняй алгоритмы.

    Игры это одно там выводятся только видимые спрайты. Через BitBlt а вся местность разбита на кводраты. Поэтомо легко узнать что выводить.

    Так насчет маштабирования и перерисовки.
    Во-первых надо сделать быстрый ресайз. Уменьшение и увиличение изоброжения.

    Так алгориты  маштобирования известны. Для быстрого доступа к пикселям используй ScanLine.

    Для  быстрого вывода используй BitBlt.

    В одном битмапе храни реальное изоброжение в другом отмаштобированное.

    Если  вывод будет не удовлетворять.
    Тогда разбей изоброжение на несколько частей, квадратов. И вывод и ресайз осуществляй только нужных облстей.

    Не плохо также было бы выравнить хранимое изображении на границе 128бит(16Байт)
    И обрабатовать используя SSE, MMX.
  • rts111 © (15.08.07 16:31) [15]
    Создай буферный битмап, и с ним работай.

    Вот примерно можно создать двумерный массив
    для быстрого доступа к отдельному пикселю битмапа:

    ...
    type

    TColor32 = packed record // или TColor24 ...
     case integer of
      0:( r,g,b,a :byte;   );
      1:( Color   :TColor; );
    end;  

    TColor32Array    = array[0..0] of TColor32;
    PColor32Array    = ^TColor32Array;
    TColor32ArrayMxN = array of PColor32Array;

    function CreatePixelArray( Pic :TBitmap ): TColor32ArrayMxN;
    var
    j :integer;
    begin
    SetLength( Result , Pic.Height );
    for j:=0 to Pic.Height-1 do Result[j]:=Pic.ScanLine[j];
    end;

    ...

    var
    qPixel = TColor32ArrayMxN;
    MyPic  = TBitmap;

    ...

    qPixel := CreatePixelArray( MyPic );
    ...
  • просто так (16.08.07 12:56) [16]
    А где можно глянуть демку этой проги? тоже интересует тема редакторов схем
  • Pa5ha © (17.08.07 15:54) [17]
    просто так, напиши в аську 2i9425i9б, i - это единицо )
  • DomiNick (12.02.09 20:12) [18]
    Спрошу уж тогда тут...

    Вот например есть некая формула...
    По этой формуле в TBitmap рисуется изображение: цикл в цикле, пробегаются все точки холста, ставится пиксель с цветом определяющимся по формуле...
    После этого "выводим его на холст TImage" меняем параметры формулы и рисуем следующий "кадр"...

    Как можно обеспечить максимальную скорость "смены кадров"..? Многое перепробовал, но самый лучший полученный результат не совсем устраивает...

    Я понимаю что при подобных способах скорость сильно зависит от сложности вычисления по формуле и размере изображения...
    Но может можно как-то заставить кадры меняться с частотой не уступающей показу видео..?

    Эх... Вероятнее всего просто сам кадр слишком долго прорисовывается...
    Там каждый кадр рисуется по довольно сложной формуле (не помню где её вычитал) и уже потом выводится на экран...
    По всей видимости ускорить уже не получится - не заставишь же Sin'усы и Cos'инусы считаться быстрее... (простые операции "+", "-", "*" и "/" не особо тормозят процесс)
  • DomiNick (12.02.09 20:36) [19]
    На всякий случай вот кусок основного кода на Делфи 7:


    {...}
    Type
         TRGB=record
               b,g,r: Byte;
         End;
         ARGB = array[0..1] of TRGB;
         PARGB=^ARGB;

    Var Bit: TBitmap;

    {...}
    Bit:=TBitmap.Create;
    Bit.PixelFormat:=pf24bit;
    Bit.Width:=Form1.Width;
    Bit.Height:=Form1.Height;
    {...}

    Procedure Draw;
    Var p: PARGB; {...} // ...и прочие переменные для вычисления цвета
    Begin
    {...} // предварительные подсчёты "полуконстант" - то что не меняется при последующих вычислениях, но генерируется случайным образом при запуске процедуры
    For y:=1 To (Form1.Height) Do
         Begin
         p:=Bit.ScanLine[y-1];
         For x:=1 To (Form1.Width) Do
               Begin
               qx:= {...} // длиннющая формула с синусами и косинусами - причём то что "под" синусами и косинусами, а также множители всяческими способами зависят от номера кадра, координат пикселя и многого другого...
               qy:= {...} // практически такая же формула... и упростить или выделить общие параметры не выходит...
               p[x-1].r:=Trunc(Abs(qy));
               p[x-1].g:=Trunc(Abs(qx+qy));
               p[x-1].b:=Trunc(Abs(qx));
               End;
         End;
    DCs:=GetDC(Form1.Handle);
    BitBlt(DCs, 0, 0, Form1.Width, Form1.Height, Bit.Canvas.Handle, 0, 0, SRCCOPY);
    ReleaseDC(Form1.Handle, DCs);
    DeleteDC(DCs);
    i:=i+1; // номер "кадра" - присутствует в "предварительных подсчётах" и "длиннющих формулах" - обеспечивает плавное изменение самого рисунка в каждом кадре...
    End;



    P.S.  Уже задавал этот вопрос на другом форуме, но сейчас решил "скопипастить" сюда - может тут кто поможет...
 
Конференция "Игры" » Быстрый канвас [Delphi, Windows, ХР]
Есть новые Нет новых   [134427   +37][b:0.001][p:0.004]