Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Быстрый канвас [Delphi, Windows, ХР]


Pa5ha ©   (05.08.07 18:53

Хотя пишу я и не игру, но вопрос, наверно, должен быть именно здесь :)
Вобщем пишу прогу для построения принципиальных схем. Движог для построений готов. Т.е. можно рисовать линии, круги, добавлять надписи, выделять по разному. Но проблема в том, что это все жутко тормозит при большом кол-ве палок на схеме. Надо бы это как-то оптимизировать. Собственно вопрос получается такой широкий. Расскажите как это делать плз ) Какие способы есть быстро нарисовать (опенГЛ врубать туда не хотелось бы)?

На данный момент есть несколько конкретных вопросов.
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.  Уже задавал этот вопрос на другом форуме, но сейчас решил "скопипастить" сюда - может тут кто поможет...


antonn ©   (13.02.09 00:34[20]

можно убрать пару строк и сделать просто
BitBlt(canvas.Handle,0, 0, Form1.Width, Form1.Height, Bit.Canvas.Handle, 0, 0, SRCCOPY);
без DC


Sapersky   (13.02.09 15:40[21]

По всей видимости ускорить уже не получится - не заставишь же Sin'усы и Cos'инусы считаться быстрее...

Заставишь, заставишь. Самый распространённый метод в софтверной графике - использование заранее просчитанных таблиц. Тебе же синусы-косинусы нужны с некоторой конечной точностью, поэтому и таблица может быть вполне приемлемого размера.
Ну и желательно использовать только целые числа (современные процессоры и floating-point считают достаточно быстро, но преобразования из одного в другое занимают много времени).


DomiNick   (14.02.09 23:10[22]

Хм... А можно поподробнее..?
Двумерную таблицу-массив? Или одномерную?
И как брать значения? Придётся округлять то что "под" синусом должно быть..?


@!!ex ©   (15.02.09 09:01[23]

> [22] DomiNick   (14.02.09 23:10)

Если хватает точности градуса, делаешь таблицу градусов.
Не хватает - таблице минут. Не хватает - в секундах.
Все расчеты соответсвтенно ведешь либо в градусах, либо в минутах, либо в секундах. Все целочисленное.
Работать будет быстро. Точности секунд уж полюбому должно хватить. ;)


Дуб ©   (16.02.09 06:46[24]

> Если хватает точности градуса, делаешь таблицу градусов.
>
> Не хватает - таблице минут. Не хватает - в секундах.

Можно линейную интерполяцию (например) использовать, чтобы не увеличивать объем таблиц.


DomiNick   (16.02.09 22:01[25]

> Можно линейную интерполяцию (например) использовать

Не знаю, что за зверь...
Можно поподробнее..? :)

И с примером кода ;)


@!!ex ©   (16.02.09 22:28[26]

> [25] DomiNick   (16.02.09 22:01)

это математика класса 10.
гугль знает.
и в разделе "ИГры" этот вопрос уже поднимался. не так давно, врядли успело уйти в архив.


Sapersky   (17.02.09 17:28[27]

В FastLIB есть пример рисования плазмы:

http://sapersky.narod.ru/files/FastLIBv389i.rar (plasma)

Используется таблица на 1024 у.е., чтобы было удобнее "обрезать" значения до нужного диапазона (and $3FF), благодаря цикличности синусов-косинусов такой трюк проходит.
По полученным значениям выбираются цвета из палитры, тоже на 1024 цвета (в режиме "Channels" для r,g,b отдельно, так что получается вполне True Color). Палитра формируется пресловутой линейной интерполяцией (FillColors) между 13-ю цветами, чтобы получить гладкие переходы.


DomiNick   (22.02.09 03:53[28]

Sapersky, благодарю... Интересные исходники... :)

Вы сделали меня ещё умнее...
Это поможет мне на пути к завоеванию Мира!)


Вася   (23.02.09 03:01[29]

А я так ничего и не понял... :(

Вот например есть число и от него нужно вычислить синус (как от радианов)...
Как тогда брать синус, например, когда "x=0,0091344521..." из таблицы??
А если нужно от отрицательного числа??
Там же тока целое-положительное число можно в A[i] подставлять...

И ещё... Синус это периодическая функция: " -1,5707963267... < x < 1,5707963267... "
и если нужно будет подсчитать синус от "x=55,66756326..." - как тогда?..


Б   (23.02.09 08:16[30]

> Как тогда брать синус, например, когда "x=0,0091344521..." из таблицы??

Ну и зачем тебе такой SIN?
Обычно делают таблицу на 360 или 720 элементов.
Таблица заполняется в начале работы программы, а потом через функции - обёртки находится нужный, уже просчитанный SIN из таблицы.
Посмотри модуль DelphiX - DXClass, правда там таблица на 256.

> " -1,5707963267... < x < 1,5707963267... "

[-1, 1]


@!!ex ©   (23.02.09 08:27[31]

> [30] Б   (23.02.09 08:16)
> [-1, 1]

[-PI,PI]


Вася   (23.02.09 15:39[32]

> [-PI,PI]

Я знаю, но у меня-то число дано именно в виде "x=0,0091344521...", а иногда выходит за промежуток [-PI,PI] ...

Придётся переводить в градусы чтоль?

> Посмотри модуль DelphiX - DXClass

Это чего такое?.. Чтот не нашёл...(


Вася   (23.02.09 15:50[33]

P.S.

Ой... Тока не [-PI,PI] , а [-PI/2, PI/2] ... :)


Б   (23.02.09 17:21[34]

> Это чего такое?.. Чтот не нашёл...(

Что не нашёл? DelphiX? Или приведённый модуль? ;)

> а иногда выходит за промежуток [-PI,PI] ...

COS любого числа, возьми хоть триллиард, никогда не выйдет за рамки промежутка [-1, 1].


Вася   (23.02.09 17:41[35]

> Что не нашёл? DelphiX? Или приведённый модуль? ;)

Ни то, ни другое... :(
Что это и зачем?.. Я ж просто на TImage рисую...

> COS любого числа, возьми хоть триллиард, никогда не выйдет за рамки промежутка [-1, 1].

Ну... Я вообще-то про SIN спрашивал... Ну не важно:

Во-первых, я там опечатался - настоящий промежуток [-PI/2, PI/2]
Известно что:
SIN(-PI/2)=-1
SIN(0)=0
SIN(PI/2)=1
А дальше уже периодически...

Но это результат вычисления синуса...

А в самих скобках же может быть число выходящее за промежуток [-PI/2, PI/2] ...

И как же тогда брать из таблицы значения SIN(х), зная только "х" ??
(Которое к томуже указано в радианах и может равняться любому произвольному числу даже не входящему в нужный промежуток)


Б   (23.02.09 17:57[36]

> Что это и зачем?...

Там просто лежит пример такой таблицы.

> Я вообще-то про SIN спрашивал...

А какая вообще разница? Промежуток всё равно у них одинаковый.


> Известно что:
> SIN(-PI/2)=-1
> SIN(0)=0
> SIN(PI/2)=1
> А дальше уже периодически...


Так я это уж сказал.

Короче, смотри здесь. Таблица не ахти (в смысле код), но оптимизацией заниматься никто не запрещал. ;)
http://www.delphikingdom.com/asp/answer.asp?IDAnswer=67402


DomiNick   (23.02.09 21:21[37]

>  > Что это и зачем?...
> Там просто лежит пример такой таблицы

И где это взять..? :)


Б   (24.02.09 04:42[38]

> И где это взять..? :)

Уже ссылка есть и в никаком DelphiX уже шариться не надо.


AssemblerWorld.Narod.Ru   (26.02.09 03:50[39]

Нифига... На ассемблере нужно писать... Ещё быстрее будет... :)


@!!ex ©   (26.02.09 08:03[40]

> [39] AssemblerWorld.Narod.Ru   (26.02.09 03:50)

Не будет.
1) Надо понимать, что современные компилятор проводят очень охренительную оптимизацию, не факт что человек в разумные сроки сможет сделать также.
2) Производсительность если и будет выше, то на копеечку. А скорость разработки упадет в разы.

Единственное что, имеет смысл операции с векторами переписать на MMX или SSE. Или пользоваться компилерами, которые сами это умеют.


Sapersky   (26.02.09 16:12[41]

Delphi, к сожалению, не относится к охренительно оптимизирующим компиляторам. Хотя, заглядывая периодически в CPU window, можно "подтюнить" паскалевский код почти до уровня asm. И лично я предпочитаю именно такой "тюнинг", используя asm только если компилятор совсем уж тупит и никак не получается его вразумить. Всё-таки паскалевский код гораздо лучше читается и легче модифицируется (пусть даже с нарушением "тюнинга", но всё же это лучше, чем сидеть и мучительно пытаться понять написанный пару лет назад столбик трёхбуквенных матов).


@!!ex ©   (27.02.09 13:03[42]

> [41] Sapersky   (26.02.09 16:12)

В принципе когда говорил об оптимизации, имел ввиду скорее С++ компиляторы, чем дельфи. Хотя и дельфи очень даже не плох.


Вася   (28.02.09 00:29[43]

Я сделал по таблице, но особого прироста скорости нету (программирую в Delphi 7)...(

Нашел ещё вычисление по вот такой функции:
[CODE]
Const                                             //глобальные
     sin1: Double=7.61e-03;
     sin2: Double=-1.6605e-01;
     sin3: Double=1;

function ASin(fAngle:Single):Single;
asm
fld fAngle.Single
fmul fAngle.Single
fld sin1.Double
fmul st(0),st(1)
fld sin2.Double
faddp st(1),st(0)
fmulp st(1),st(0)
fadd sin3.Double
fmul fAngle
end;
[/CODE]

Считает в два раза быстрее таблиц, но точность сильно хромает...
Да и как-то не пойму для какого промежутка fAngle синус от него считается правильно...

Кто-нибудь может объяснить как этот код вообще работает и на каком он языке?
Ну и улучшить его точность хотя бы до 5-го знака после запятой?


@!!ex ©   (28.02.09 08:41[44]

> Считает в два раза быстрее таблиц, но точность сильно хромает...
> Да и как-то не пойму для какого промежутка fAngle синус
> от него считается правильно...

Вообще гнаться за скоростью работы синуса сейчас смысла особо нету...


> Кто-нибудь может объяснить как этот код вообще работает
> и на каком он языке?
> Ну и улучшить его точность хотя бы до 5-го знака после запятой?

Язык - ассемблер. Как работает - х.з., видимо использует какую-то приближенную форумулу вычисления.
Улучшить врядли получится.


Б   (28.02.09 10:59[45]

> Я сделал по таблице, но особого прироста скорости нету (программирую в > Delphi 7)...(

Не может быть.

Если нужно вычислить срузу и COS и SIN, то процедура Math.SinCos, сделает это в 2 раза быстрее, чем их вычисление по одиночке.


Pavia ©   (28.02.09 14:32[46]


> 1) Надо понимать, что современные компилятор проводят очень
> охренительную оптимизацию, не факт что человек в разумные
> сроки сможет сделать также.2) Производсительность если и
> будет выше, то на копеечку. А скорость разработки упадет
> в разы.

1) А ты сам проверял? Вся эта охренительная оптимизация ломается как только идут вместо констант вычисление чего либо. На циклах компилятор уже плохует. Где-то получше где-то похуже. Человек запросто обгоняет компилятор. И это я говорю о компиляторе от МС. При этом Delphi отстает не намного.

2) Прирост скорости от 2 раз до 50раз (к примеру БПФ от интел в 30раз быстрее прямой реализации). А вот скорость разработки упадет.


> Не может быть.
Может скорость вычисления синуса на современных процессорах составляет менее 120 тактов. Наиболее быстрым вариантам считается вычисление синуса на месте используя приблеженные формулы. У интел есть математическая библиотека в ней можно глянуть различные варианты.


@!!ex ©   (28.02.09 14:40[47]

> 1) А ты сам проверял? Вся эта охренительная оптимизация
> ломается как только идут вместо констант вычисление чего
> либо. На циклах компилятор уже плохует. Где-то получше где-
> то похуже. Человек запросто обгоняет компилятор. И это я
> говорю о компиляторе от МС. При этом Delphi отстает не намного.


Я сам читал кучу тестов.
Плюс насколько я вижу, ни одна здравомыслящая компания не делает игры на ассемблере.
Да и вообще только полный идиот(ИМХО), будет писать всю игру на ассемблере. АСМ вставки в критичных местах - это максимум.


DomiNickDark   (28.02.09 17:25[48]

> ни одна здравомыслящая компания не делает игры на ассемблере

Делает... :))

Вот пример: http://dominickdark.narod.ru/Farbrausch-Games.Html


@!!ex ©   (28.02.09 17:48[49]

> [48] DomiNickDark   (28.02.09 17:25)

Это For Fun Only.


имя   (28.02.09 22:34[50]

Удалено модератором


Вася   (01.03.09 02:18[51]

>  Не может быть.

Может...((

У меня жуткая формула... А нужно пересчитать её для каждого пикселя изображения...(
На весь мой экран получаются миллионы вычислений синуса...((

Может как-то сделать полноэкранный режим лучше будет?
При размере "канваса" 800х600 скорость ещё сносная выходит...


имя   (01.03.09 02:20[52]

Удалено модератором


Вася   (01.03.09 02:24[53]

Э... И что в этой анкете искать?..


Дуб ©   (01.03.09 05:11[54]


> У меня жуткая формула... А нужно пересчитать её для каждого
> пикселя изображения...(
> На весь мой экран получаются миллионы вычислений синуса.
> ..((

Для экрана? Для каждого пиксела? И вся эта информация визуально значительна? А логи на 100 метров, мы в туалете на релаксацию читаем?


Pavia ©   (01.03.09 09:34[55]


> У меня жуткая формула... А нужно пересчитать её для каждого
> пикселя изображения...(На весь мой экран получаются миллионы
> вычислений синуса...((

А зачем там что синусы меняются? Если меняются то неплохобы знать закономерность.
А если не меняются то их вычислить заранее вне цикла.


Б   (01.03.09 10:19[56]

2 Вася
> У меня жуткая формула...

Что-то не упомянул, каким способом выводишь график.
И вообще, что ты делаешь?


Sapersky   (01.03.09 19:00[57]

Кто-нибудь может объяснить как этот код вообще работает

Скорее всего разложение в ряды Тейлора.

У меня жуткая формула... А нужно пересчитать её для каждого пикселя изображения...(
На весь мой экран получаются миллионы вычислений синуса...((


См. [27]. Тоже синусы-косинусы через таблицы, и ничего не тормозит.


Вася   (01.03.09 23:44[58]

>>> Для экрана? Для каждого пиксела? И вся эта информация визуально значительна? А логи на 100 метров, мы в туалете на релаксацию читаем?

Что-то не понял, что вы имели ввиду...

>>> А зачем там что синусы меняются? Если меняются то неплохо бы знать закономерность

В том-то и дело, что меняются... Причём некоторые коэффициенты рэндомом... :(

>>> Тоже синусы-косинусы через таблицы, и ничего не тормозит

Для 800х600 не тормозит... А на весь экран - тормозит... :(

>>> Что-то не упомянул, каким способом выводишь график. И вообще, что ты делаешь?

Почему "график"? Для графика не нужно было бы все пиксели перебирать...

Я свой СкринСейвер делаю... :)

Правда нормального примера исходника СкринСейвера на Делфи7 так и не нашел...
Самих примеров-то множество (хотя б на "ДелфиВорлд"), но каждый как-то по своему глючит... :(


@!!ex ©   (02.03.09 00:00[59]

у меня 1680х1050 фуллскрин несколько обработок всех пикселей всего экрана(и там далеко не только вычисление синуса) не тормозит...
а почему? А потому что пиксели экрана эта та штука, которую надо считать на видухе, а не на ЦПУ.


Вася   (02.03.09 00:11[60]

>>> А потому что пиксели экрана эта та штука, которую надо считать на видухе, а не на ЦПУ.

Ого..... Научите? :)


Дуб ©   (02.03.09 05:59[61]


> Вася   (01.03.09 23:44) [58]
> >>> Для экрана? Для каждого пиксела? И вся эта информация
> визуально значительна? А логи на 100 метров, мы в туалете
> на релаксацию читаем?
>
> Что-то не понял, что вы имели ввиду...


Тут надо понять, что надо. Сомнения, что для нормальных fps нужно просчитывать очень сложно весь экран попиксельно самому. А для статики - странно что "тормозит".

Возможно тормоза не там, а в выводе на канвас и т.п. В общем 17-я строка пока.


@!!ex ©   (02.03.09 11:27[62]

> [60] Вася   (02.03.09 00:11)

GLSL?


Вася   (02.03.09 16:18[63]

Кто это? :)


Sapersky   (02.03.09 16:21[64]

Для 800х600 не тормозит... А на весь экран - тормозит... :(

Я как раз намекаю на то, что пример plasma, при всей внешней схожести методов, как-то умудряется выдавать 77 FPS на Cel 2.8 и 1280*1024.
Могу сказать конкретно - основная причина в использовании только целых чисел, я об этом писал ещё в [21], а также в отсутствии ветвлений (if) и прочих вредных для производительности вещей.

Насчёт "видюхи" я тоже не имею ничего против. Неплохо знать разные методы работы с графикой, чтобы выбирать наилучший для каждой конкретной задачи. Можно применять смешанный подход - например, рассчитывать уменьшенную картинку софтверно и потом увеличивать её аппаратно.

Правда, использование продвинутых функций аппаратной графики вроде GLSL несколько сужает диапазон железа, на котором оно может пойти.


@!!ex ©   (02.03.09 16:41[65]

> [64] Sapersky   (02.03.09 16:21)
Правда, использование продвинутых функций аппаратной графики вроде GLSL несколько сужает диапазон железа, на котором оно может пойти.

Если забыьт о моем любимом интеле, то будет работать на всех видеокартах не старше лет 4.


Дуб ©   (02.03.09 17:34[66]


> на всех видеокартах не старше лет 4.

А стоит ли тех жертв, пока в 17-й строке ковыряемся?

> Вася   (02.03.09 16:18) [63]

Я бы, все-таки подумал для начала о том о чем говорил - о нужности расчитываемого отображаемого объема информации(на мое имхо - там перегрузка мозга, по минимуму), а на первый проход - о методах вывода, без вычислений. Просто без вычислений - как у вас заполянется весь канвас, словно те вычисления есть, но пустые?


Вася   (02.03.09 22:14[67]

Я не понимаю про что вы... :(

17-я строка чего?..

Как в Делфи заставить производить вычисления и прорисовку кадра на видеокарте?..


Дуб ©   (03.03.09 05:42[68]

> Вася   (02.03.09 22:14) [67]

Я тебе не про видеокарту. Я не знаю как ты наносишь данные на канву. Первые тормоза оттуда идут обычно.

И второе, про что говорю, - насколько это важно тебе в своем коде мурыжить жестко каждый пиксел.


Вася   (03.03.09 06:11[69]

>>> насколько это важно тебе в своем коде мурыжить жестко каждый пиксел

А как по-другому-то?

>>> Я не знаю как ты наносишь данные на канву. Первые тормоза оттуда идут обычно.

Хм... А можете тогда сразу объяснить (не разбирая моих возможных ошибок по незнанию) как правильнее делать? :))


Дуб ©   (03.03.09 06:31[70]

> Вася   (03.03.09 06:11) [69]

0. Я не знаю твоих задач.
1. Если нужна динамичная картинка, то применять кучу синусов косинусов для каждого пиксела самому - может быть странно. Большинство пикселов проще просто интерполировать по некоторым соседям.
2. Неа. Но если для канваса - то не пользовать для начала Canvas.Pixel[i,j], а прочитать для начала статью "Поставить точку". Об этом уже было в ветке.


Вася   (03.03.09 20:28[71]

>>> проще просто интерполировать по некоторым соседям

У меня случайное изображение... Сомневаюсь что оно как-то так делается...

Вобщем так:
Рисую в переменной типа TBitmap, используя метод (или как там его правильнее) TPARGB:=Bit.ScanLine[i];
После этого рисую этот TBitmap на холсте (не важно - на TImage или TForm)

Правда тут вот ещё такой вопрос...
Нашёл вот такую информацию (цитаты у меня чтот не работают, уж извините так напишу)

<<< Быструю графику не делают на элементе TTimer. Он не способен (или был раньше не способен?) выдавать события чаще чем через 55 мс (интервал = 1 не будет реализован), то есть TTimer в делфи не может вызываться раз в миллисекунду... Даже если поставить Timer.Interval:=1; то он всё равно будет вызываться примерно раз в 55 миллисекунд, а не раз в 1... >>>

А у меня как раз TTimer кадры меняет..... :(

Я уже и не знаю - не хватает ли скорости синуса или тут уже сам вывод тормозит.....


Sapersky   (03.03.09 23:46[72]

Даже если поставить Timer.Interval:=1; то он всё равно будет вызываться примерно раз в 55 миллисекунд, а не раз в 1

Так и есть, хотя для некоторых случаев 18-20 FPS хватает.
Если нужно быстрее - используй Application.OnIdle с Done = False (см. справку).

Я уже и не знаю - не хватает ли скорости синуса или тут уже сам вывод тормозит

Так замерять нужно.
В начале измеряемого блока TimeReset, в конце TimeMs/TimeShowMs, покажет время в миллисекундах:

Var
 PCFreq, PCTime1, PCTime2 : Int64;

procedure QueryPerformanceCounter(Var Cnt : Int64);
Var Thread, OldMask : DWord;
begin
// force the thread to CPU 0 for multi-core CPU
Thread := GetCurrentThread; OldMask := SetThreadAffinityMask(Thread, 1);

// update counter frequency for CPUs with variable clock rate (Athlon64, Pentium M)
QueryPerformanceFrequency(PCFreq);
Windows.QueryPerformanceCounter(Cnt);

// restore threads
SetThreadAffinityMask(Thread, OldMask)
end;

procedure TimeReset;
begin
QueryPerformanceCounter(PCTime1);
end;

function TimeMs: Integer;
begin
QueryPerformanceCounter(PCTime2);
Result:=( (PCTime2-PCTime1) * 1000 ) div PCFreq;
PCTime1:=PCTime2;
end;

procedure TimeShowMs;
Var i : Integer;
   s : String;
begin
i := TimeMs; Str(i, s);
MessageBox(0, PChar(s), 'Time elapsed, ms ', MB_OK or MB_ICONWARNING);
end;


Дуб ©   (04.03.09 05:54[73]

> У меня случайное изображение... Сомневаюсь что оно как-то
> так делается...

Ситуация в том, что каждая картинка - 1 том Войны и Мира. И таких томов ты хочешь давать - ну 20 в секунду. Кто такое воспринимает? Отсюда и не надо плясать над каждым пикселом. А уж если идет рендеринг - так его на железо лучше и повесить, а не рендерить самому.

> Рисую в переменной типа TBitmap, используя метод (или как
> там его правильнее) TPARGB:=Bit.ScanLine[i];

Прочитай статью "Поставить точку".

http://www.delphimaster.ru/articles/pixels/index.html

Ну, и как сказали - надо померить.


Pavia ©   (04.03.09 08:35[74]


> У меня случайное изображение... Сомневаюсь что оно как-то
> так делается...

Так ты напиши что ты там делаешь иначе тебе никто не поможет. И нечего скрывать никто твои идее тырить не собирается.

Ошибка в том что ты неправельно делаешь.
А судя по описанием ты реализуешь плазму?
Так она недолжна тормазить.
Не зная что-ты делаешь нельзя посоветовать и сказать, что не так.


antonn ©   (05.03.09 01:54[75]


> > Рисую в переменной типа TBitmap, используя метод (или
> как
> > там его правильнее) TPARGB:=Bit.ScanLine[i];
>
> Прочитай статью "Поставить точку".

собственно, примерно это он и делает.


Дуп   (05.03.09 05:11[76]


> antonn ©   (05.03.09 01:54) [75]
>
> > > Рисую в переменной типа TBitmap, используя метод (или
>
> > как
> > > там его правильнее) TPARGB:=Bit.ScanLine[i];
> >
> > Прочитай статью "Поставить точку".
>
> собственно, примерно это он и делает.

ой ли?


MBo ©   (05.03.09 07:11[77]

>ой ли?
По большому счету - да. Суть ведь одна - прямое обращение к блоку цветовых данных. Разница в удобстве.


Б   (05.03.09 10:03[78]

> А судя по описанием ты реализуешь плазму?

Нет, он делает скринсервер, с целой кучей вычислений синусов и косинусов. ;D
(Вася   (01.03.09 23:44) [58] )

> Почему "график"? Для графика не нужно было бы все пиксели перебирать...

"График" - Ошибка: ГрафикА.


Б   (05.03.09 10:31[79]

http://www.delphimaster.ru/cgi-bin/forum.pl?id=1216362230&n=7


Дуб ©   (05.03.09 10:37[80]

> MBo ©   (05.03.09 07:11) [77]

Пас.


antonn ©   (05.03.09 12:53[81]


> Дуп   (05.03.09 05:11) [76]


Но в случаях просчета именно "синусов/косинусов" со сканлайном могут быть тормоза больше обычного, если кривая строится по вычисляемым точкам и практически для каждой точки берется bt.scanline[y] со всей строкой пикселов, а сканлайн максимально эффективно используется как раз для "разового" прохода по X - т.е. можно пробегать по холсту и смотреть, является ли такая точка частью кривой, а не наоборот, в общем с другой стороны рисовать :)


Вася   (08.03.09 21:43[82]

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

Я не проверяю никаких кривых, я считаю для каждого пиксела собственный синус... Там нету кривых...

А вот есть ли способ рисовать быстрее чем на TBitmap? Может сделать массив какой, а потом его быстро в TBitmap конвертировать? Можно так?


Pavia ©   (08.03.09 23:06[83]

Дело не в том что использовать, а в том как использовать. А ты неговоришь что да как.  Поэтому тебе помочь неполучается.


> Я не проверяю никаких кривых, я считаю для каждого пиксела
> собственный синус..

А зачем считать собственный синус если числа случайные?
Следовательно не случайные. И можно отказаться от расчета синуса к более быстрой операции, на основе закономерности Но так как ты так и несказал какие операции ты используешь то ответить невозможно.


> А вот есть ли способ рисовать быстрее чем на TBitmap? Может
> сделать массив какой, а потом его быстро в TBitmap конвертировать?
>  Можно так?

А чем тебе TBitmap не угодил? Такой же массив при условии правильного использования. А ты до сих пор не доказал что его используешь правильно.


> >>> т.е. можно пробегать по холсту и смотреть, является
> ли такая точка частью кривой, а не наоборотЯ не проверяю
> никаких кривых, я считаю для каждого пиксела собственный
> синус... Там нету кривых...

А синус что не кривая?


DomiNickDark   (08.03.09 23:38[84]

> А синус что не кривая?
Хех... Синус - это периодическая тригонометрическая функция... :)

Вася, есть нормальный материал по созданию СкринСейвера в Делфи7..? А то решил из своей графики тоже скринсейвер делать, а все найденные исходники глючные какие-то... :(

P.S. А как ты этот кадр выводишь? Пробовал так?:
BitBlt(Form1.Canvas.Handle, 0, 0, Form1.Width, Form1.Height, Bit.Canvas.Handle, 0, 0, SRCCOPY);


Pavia ©   (09.03.09 01:37[85]


> Вася, есть нормальный материал по созданию СкринСейвера
> в Делфи7..? А то решил из своей графики тоже скринсейвер
> делать, а все найденные исходники глючные какие-то... :(

У меня где-то был.
Минимальный это просто переименовать exe в scr и растянуть форму на весь экран и стиль применить . И по движению мыши и нажатию клавишы выходить.

Набросал простой пример. FPS ограничен таймером мне быстрее просто не нужно было.

Неплохая плазма получилась, прям как в ламе.
http://slil.ru/27034240


Вася   (09.03.09 22:57[86]

Э... А объясните как это работает, пожалуйста...


Procedure Plasm;
var LL, i, j: Integer; p: PByteArray;
begin
LL:=DWord(bp.ScanLine[1])-DWord(bp.ScanLine[0]);
p:=bp.ScanLine[0];
for j:=0 to bp.Height-1 do
     begin
     for i:=0 To bp.Width-1 do
           begin
           p[i*3+0]:=(CosTable1[(i +c) and (2048-1)]+CosTable1[(i+3242) and (2048-1)]+CosTable2[(j) and (2048-1)]-SinTable1[c and (2048-1)]+128*256) shr 8;
           p[i*3+1]:=(CosTable1[(i +c) and (2048-1)]{-SinTable1[c and (2048-1)]}+128*256) shr 8;
           p[i*3+2]:=(CosTable2[(j ) and (2048-1)]{-SinTable1[c and (2048-1)]}+128*256) shr 8;
           end;
     Inc(DWord(p),LL);
     end;
end;


Почему ScanLine делается только для нулевой (первой) строки, что есть "PByteArray" и что за странные индексы такие - "p[i*3+0]"...

>>> А ты до сих пор не доказал что его используешь правильно

Ну так покажите, как правильно... :))


Vetal   (09.03.09 23:39[87]


> Почему ScanLine делается только для нулевой (первой) строки


Определяется сдвиг LL на который и инкрементируется указатель - р (Inc(DWord(p),LL)).


> что за странные индексы такие - "p[i*3+0]"


Незабываем, что 24 бит изображение состоит из трёх компонент - R, G, B.


Pavia ©   (10.03.09 01:31[88]


> Э... А объясните как это работает, пожалуйста...

Как напичанно так и работает. Чистая импровизация.
В  CosTable1 предварительно вычесленные значения. shr 8 нужно для округления так как использую формат с фиксированной точкой. Нужно для оптимизации.


> ScanLine делается только для нулевой (первой) строки

Так захотелось особенно плюсов недает экономью на вызовах.

PByteArray это основной тип, про него все написанно в справке. Можно и свой тип определить.


> за странные индексы такие - "p[i*3+0]"
А чего тут странного? У меня формат битмепа 24битный.
Только напомню что цвета идут в порядке B G R. И строки в обратном порядке. Поэтому LL отрицательное. И из завыравнивания отличается от -Width*3.


> Ну так покажите, как правильно... :))

В интернете по этому делу полно статей.


DomiNickDark   (11.03.09 21:07[89]


> Как напичанно так и работает. Чистая импровизация.


Pavia, твоя импровизация?) Можешь ещё сымпровизировать?))

А я тогда померяю, как быстрее будет...))

P.S. СкринСейвер хороший, а вот как сделать, чтоб он в "предпросмотре" показывался?


Вася   (12.03.09 22:24[90]

>>> В интернете по этому делу полно статей

Ага... Например эта... Просто не хотите помочь?..

Может хоть кто-то рассказать варианты от простого к сложному?.. :(


Pavia ©   (12.03.09 23:18[91]


> Ага... Например эта... Просто не хотите помочь?.

h_ttp://democoder.ru/
h_ttp://www.hugi.scene.org/
h_ttp://www.enlight.ru/faq3d/main.htm
h_ttp://www.enlight.ru/demo/faq/index.phtml
h_ttp://algolist.manual.ru/graphics/index.php
И тд.

Ф.Хилл OpenGL. Программирование компьютерной графики

Так что это вы сами не хотите себе помочь.


> Может хоть кто-то рассказать варианты от простого к сложному?
> .. :(
Это не школа. Нужно самому учиться. Вот если есть конкретные вопросы то на них можно ответиь.


Вася   (13.03.09 22:15[92]

Я спрашивал про самый быстрый способ нарисования изображения попиксельно на Canvas...
Без использования всяких OpenGL...

Не знаете - так и скажите...

:(


@!!ex ©   (13.03.09 23:29[93]

> P.S. СкринСейвер хороший, а вот как сделать, чтоб он в "предпросмотре"
> показывался?

Гугл знает.
Если вкратце, то скринсейвер запускается со спец ключом и хэндлом окна на котором рисовать предпросмотр.


> [92] Вася   (13.03.09 22:15)
> Я спрашивал про самый быстрый способ нарисования изображения
> попиксельно на Canvas...
> Без использования всяких OpenGL...
>
> Не знаете - так и скажите...

Бред. Как связан расчет косинуса со скоростью вывода пикселей на кэнвас?
1) В любом месте и везде вам скажут использовать OGL или D3D для этих целей(могут еще DDraw посоветовать, но это смысла не имеет).
2) Если так хочеться считать всякую хрень, то лучше пиксели хранить в отдельном массиве, считать там, а потом через сканлайн вываливать блоки. Буде быстрее. Правда не на много.
3) Переделайте нафиг архитектуру и методику расчета. Ибо любой тормозящий скринсейвер идет в трэш.


Pavia ©   (13.03.09 23:36[94]


> Я спрашивал про самый быстрый способ нарисования изображения
> попиксельно на Canvas...Без использования всяких OpenGL.
> ..Не знаете - так и скажите...

Математика она и в африке математика и в OpenGL таже самая математика.


> Не знаете - так и скажите...:(

Не хочешь учится так и скажи. B)


DomiNickDark   (16.03.09 01:49[95]


> Гугл знает.
> Если вкратце, то скринсейвер запускается со спец ключом
> и хэндлом окна на котором рисовать предпросмотр.


Про спец ключи я знаю...
У меня есть множество готовых исходников на Делфи 7, но ни в одном предпросмотр не работает как надо...
Либо при открытии вкладки "Заставка" он запускается, либо вообще никакой видимой реакции...

Есть только один СкринСейвер, в котором предпросмотр срабатывает, но при открытии вкладки "Заставка" всё окошко "Свойства: Экран" наглухо зависает минуты на две... И при выборе этого СкринСейвера в списке тоже самое... :(


> Может хоть кто-то рассказать варианты от простого к сложному?
> .. :(


Могу... :)
"от простого", значить, "к сложному".....

Вариант №1 - самое простое и банальное:


Procedure Draw;
Var x, y: Integer; Bitmap: TBitmap;
Begin
Bitmap:=TBitmap.Create;
Bitmap.PixelFormat:=pf24bit;
Bitmap.Width:=640;
Bitmap.Height:=480;
For y:=0 To Bitmap.Height-1 Do
For x:=0 To Bitmap.Width-1 Do
 Bitmap.Canvas.Pixels[x, y]:=RGB(x+x, x+y, y+y);
Form1.Canvas.Draw(0, 0, Bitmap);
End;


DomiNickDark   (16.03.09 02:19[96]

Вариант №2 - с использованием "ScanLine":


Procedure Draw2;
Type
 TRGB=Record Blue,Green,Red: Byte End;
 ARGB = Array[0..0] Of TRGB;
 PARGB=^ARGB;
Var x, y: Integer; Bitmap: TBitmap; Line: PARGB;
Begin
Bitmap:=TBitmap.Create;
Bitmap.PixelFormat:=pf24bit;
Bitmap.Width:=640;
Bitmap.Height:=480;
For y:=0 To Bitmap.Height-1 Do
 Begin
 Line:=Bitmap.ScanLine[y];
 For x:=0 To Bitmap.Width-1 Do
   Begin
   Line[x].Red:=x+x;
   Line[x].Green:=x+y;
   Line[x].Blue:=y+y;
   End;
 End;
Form1.Canvas.Draw(0, 0, Bitmap);
End;


Работает примерно в 45 раз быстрее, чем "Вариант №1"... :)


DomiNickDark   (16.03.09 02:32[97]

Пробовал вариант от Pavia


Procedure Draw2_5;
Var x, y, dx: Integer; Bitmap: TBitmap; Pixels: PByteArray;
Begin
Bitmap:=TBitmap.Create;
Bitmap.PixelFormat:=pf24bit;
Bitmap.Width:=640;
Bitmap.Height:=480;
dx:=DWord(Bitmap.ScanLine[1])-DWord(Bitmap.ScanLine[0]);
Pixels:=Bitmap.ScanLine[0];
For y:=0 To Bitmap.Height-1 Do
 Begin
 For x:=0 To Bitmap.Width-1 Do
   Begin
   Pixels[x*3+0]:=y+y;
   Pixels[x*3+1]:=x+y;
   Pixels[x*3+2]:=x+x;
   End;
 Inc(DWord(Pixels), dx);
 End;
Form1.Canvas.Draw(0, 0, Bitmap);
End;


но он оказался чуть медленнее, чем "Вариант №2"... :(


@!!ex ©   (16.03.09 08:09[98]

> [95] DomiNickDark   (16.03.09 01:49)
> Про спец ключи я знаю...

Тогда мне не понятна проблема. :)


Sapersky   (16.03.09 14:05[99]

но он оказался чуть медленнее, чем "Вариант №2"... :(

А у меня вариант Pavia быстрее, причём весьма прилично, почти в 2 раза.
Основная причина - TBitmap.Scanline, точнее, функция GetScanline, в которой выполняется масса телодвижений весьма сомнительной полезности. В некоторых случаях они, может, и нужны, но скорости точно не добавляют.

Я тут приводил ссылку на FastLIB... так вот, там эти моменты, в отличие от TBitmap, хорошо продуманы:
1) Scanline - это заранее заполненный массив указателей, никаких функций не вызывается. Или, в качестве альтернативы, есть свойства BWidth (= dx из примера Pavia) и Gap (BWidth - Width * BytesPerPixel).
2) Быстрое свойство Pixels с привязкой к конкретному формату (Pixels8,Pixels24), без вызова функций. Полезно при выборе данных из произвольного места картинки (при последовательном обходе быстрее сканлайн).
3) Удобная работа с палитрой (см. тот же пример plasma). В TBitmap она
вообще никакая.
4) Много готовых спецэффектов (FastFX.pas). Полезно не только в смысле использовать, но и чтобы поучиться, как писать свои.
5) Сам класс TFastDIB - гораздо более "тонкая" обёртка над DIB. Хотя в общем код не отличается понятностью, но при необходимости разобраться в "кишках" всё же проще, чем перелопачивать тонны кода TBitmap.
Можно создавать TFastDIB и без DIB, просто на блоке памяти. Или "навешивать" на уже выделенный блок...
6) Ещё одно следствие "тонкости" - минимум автоматизации и в целом более предсказуемое поведение. Для новичка, может, автоматизация и полезна, но у человека сколь-нибудь опытного попытки класса-картинки заниматься "самодеятельностью" вызывают только раздражение (например, при изменении размера/bpp картинки "шибко умный" TBitmap пытается преобразовать картинку под новый формат, что нужно далеко не всегда; при этом занимает время/жрёт память).

Есть некий "промежуточный" между TBitmap и TFastDIB вариант - TDIB из DelphiX (к DirectX он никакого отношения не имеет), ну и масса других классов/библиотек...


Pavia ©   (16.03.09 15:37[100]


> А у меня вариант Pavia быстрее, причём весьма прилично,
> почти в 2 раза.

У меня тоже прерирост но только в 1.33. И Эта цифра тем  больше чем больше разрешение изоброжения. Я предпочитаю тестировать на 1024х1024.

Можно такой код попробовать. Он дал еще прирост еще на 10% процентов по сравнению с Draw2_5.

Ище в коде добавил Bitmap.Free; от утечек памяти. И то они тестирование сбивают.

Procedure Draw2_6;
Var x, x3, y, dx : Integer; Bitmap: TBitmap; Pixels: PByteArray;
Begin
Bitmap:=TBitmap.Create;
Bitmap.PixelFormat:=pf24bit;
Bitmap.Width:=640;
Bitmap.Height:=480;
dx:=DWord(Bitmap.ScanLine[1])-DWord(Bitmap.ScanLine[0]);
Pixels:=Bitmap.ScanLine[0];
For y:=0 To Bitmap.Height-1 Do
Begin
 x:=Bitmap.Width-1;
 repeat
  Pixels[x*3+0]:=y+y;
  Pixels[x*3+1]:=x+y;
  Pixels[x*3+2]:=x+x;
  dec(x);
 until x<=0;
Inc(DWord(Pixels), dx);
End;
Form1.Canvas.Draw(0, 0, Bitmap);
Bitmap.Free;
End;


 x:=Bitmap.Width-1;  Вызов объекта сбивает оптимизатор дельфи.
Лучше завести переменную Width:=Bitmap.Width-1 и ее использовать.


DomiNickDark   (17.03.09 11:53[101]

Думаю скорость ещё и от самой машины зависит...
Вот на моей машине "Вариант № 2_6" чуть быстрее "Варианта № 2"...

> Ище в коде добавил Bitmap.Free; от утечек памяти. И то они тестирование сбивают.

Да... Это я как-то маху дал... :(
Я просто обычно использую тока один Bitmap: При создании формы создаю Bitmap, а уже при закритии программы уничтожаю его...

> x:=Bitmap.Width-1;  Вызов объекта сбивает оптимизатор дельфи.
> Лучше завести переменную Width:=Bitmap.Width-1 и ее использовать.


Мда..? Не знал... А чем это объясняется? :)

> > Про спец ключи я знаю...
> Тогда мне не понятна проблема. :)


Проблема проста - предпросмотр СкринСейвера не работает.....


@!!ex ©   (17.03.09 11:57[102]

> > > Про спец ключи я знаю...
> > Тогда мне не понятна проблема. :)
>
> Проблема проста - предпросмотр СкринСейвера не работает.....

О ключе вы знаете. Хэндл есть.
Почему не работает?


Sapersky   (17.03.09 15:55[103]

У меня тоже прерирост но только в 1.33.

Сейчас проверил на другом компе - 1.23. Видимо, в 1-ом случае повлияла Win98, наверное, какие-то системные функции там выполняются медленнее.

Можно такой код попробовать. Он дал еще прирост еще на 10% процентов по сравнению с Draw2_5.

Более удачное распределение переменных по регистрам получилось. В первом варианте счётчик цикла был на стеке, во втором - в регистре.

x:=Bitmap.Width-1;  Вызов объекта сбивает оптимизатор дельфи.
Лучше завести переменную Width:=Bitmap.Width-1 и ее использовать.


Но в приведённом примере разницы почему-то нет :)
Скорее, вреден вызов функции (GetWidth), но он делается один раз на скан-линию, так что это не принципиально.
А если без вызова - в худшем случае 2 mov (получаем адрес объекта + получаем свойство) супротив одного. Во внутреннем цикле может иметь значение, и то небольшое.


Дуб ©   (17.03.09 16:54[104]

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

Брюзжу, да.


Вася   (17.03.09 20:37[105]

DomiNickDark, Pavia, Спасибо)
А как ещё ускорить можно не знаете? ;)


MBo ©   (18.03.09 09:13[106]

>А как ещё ускорить можно не знаете? ;)
А зачем?


Pavia ©   (18.03.09 17:44[107]


> А как ещё ускорить можно не знаете? ;)

Знаем. Можно сделать раскрутку цикла. еще 28% процентов прироста

Procedure Draw2_7;
Var x, x3, y, dx,xx,yy : Integer; Bitmap: TBitmap; Pixels: PByteArray;
Begin
Bitmap:=TBitmap.Create;
Bitmap.PixelFormat:=pf32bit; // Быстрее заработало.
Bitmap.Width:=SWidth; // Просто константы тестировать удобнее
Bitmap.Height:=SHeight;
dx:=DWord(Bitmap.ScanLine[1])-DWord(Bitmap.ScanLine[0]);
Pixels:=Bitmap.ScanLine[0];
For y:=0 To Bitmap.Height-1 Do
Begin
 yy:=y+y; // Вынес из цикла
 x:=Bitmap.Width-4;
 repeat
  xx:=x+x;
  Pixels[x*4+0]:=yy;
  Pixels[x*4+4]:=yy;
  Pixels[x*4+8]:=yy;
  Pixels[x*4+12]:=yy;
  Pixels[x*4+2]:=xx;
  Pixels[x*4+6]:=xx+2;
  Pixels[x*4+10]:=xx+6;
  Pixels[x*4+14]:=xx+8;
  Pixels[x*4+1]:=x+y;
  Pixels[x*4+5]:=x+y+1;
  Pixels[x*4+9]:=x+y+2;
  Pixels[x*4+13]:=x+y+3;
  dec(x,4);
 until x<=0;
Inc(DWord(Pixels), dx);
End;
Form1.Canvas.Draw(0, 0, Bitmap);
Bitmap.Free;
End;

У меня процедура выполняется со средней скоростью 14тик на пиксель. Что неплохо.
Дальше еще можно задействовать многоядерность и перейти к ассемблеру и воспользоваться sse.


Pavia ©   (18.03.09 18:29[108]

Из этих 14 тиков 5 уходит на очистку при создании и 5 при копировании через Draw.


DomiNickDark   (18.03.09 20:36[109]

> Знаем. Можно сделать раскрутку цикла. еще 28% процентов прироста

Ого...
Pavia, да Вы спец...
Вы, случайно, не увлекаетесь ДемоСценами? :)

> Дальше еще можно задействовать многоядерность и перейти
> к ассемблеру и воспользоваться sse.


Я и до "2_7" навряд ли бы додумался, а ещё "дальше" мне будет "рановатто"...
"Учиться, учиться и учиться..."

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

Можете посоветовать проверенные книги для дальнейшей оптимизации и ускорения..?
На будущее..... :)


antonn ©   (19.03.09 00:17[110]


> Дальше еще можно задействовать многоядерность

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


Pavia ©   (19.03.09 01:40[111]


> имхо, накладные расходы все перекроют, поможет если изображения
> огромные, в разных потоках поочередно рисовать.

А если так. Напримере двух ядер. Первый поток рисует четные строчки второй нечетные?
Потоки не перекрываются задачу распаралелили. Наклодные рассходы минимальны, при правельной организации памяти. Или первый кадр ресует один поток второй кадр другой поток. Подготовка данных идет тоже в два потока в два разных буфера.
Обработка изоброжений давно уже удачно паралелится. Да и редеринг тоже пробуют и говорят весьма удачно.


Б   (19.03.09 16:12[112]

> А как ещё ускорить можно не знаете? ;)

Сдвиговые операции самые быстрые.
Воспользоваться готовыми таблицами.
Развёртка циклов - хороший способ оптимизации.
Воспользоваться Ассемблером.
Загнать рисунок в массив и работать потом с ним.
Работать с растром через указатель - напрямую и т.д.

> Pavia [107]
Локальные переменные можно и неудалять, процедура на выходе, сделает это за нас.
Лучше умножить x на 4 один раз, вместо 12.


Pavia ©   (19.03.09 16:27[113]


> Локальные переменные можно и неудалять, процедура на выходе,
>  сделает это за нас. Лучше умножить x на 4 один раз, вместо
> 12.

Память под объекты выделяется в куче поэтому компилятер не очещает памить за ними. Нужно делать ручками.
А вот x*4 компилятор считает один раз вместо 12.


DomiNickDark   (19.03.09 22:18[114]

Хм... Терминов "раскрутка цикла" и "развёртка цикла" раньше не встречал... Про их где-нибудь пишут в книгах?

При тестировании (на 1024х1024) сбоку слева недорисовывалась часть битмапа... Белая полоска получалась...
Поменял "until x<=0;" на "until x<0;" - стало нормально... :)

И ещё чуть коэффициенты чуть подправил:

Pixels[x*4+6]:=xx+2;
Pixels[x*4+10]:=xx+4;
Pixels[x*4+14]:=xx+6;


И ещё нужно бы сказать, что выносить из цикла "yy:=y+y;" выгодно только для конкретного примера "RGB(x+x, x+y, y+y);"...
Так, на всякий... :)

Пробовал сразу по 8 пикселов в цикле считать... Еле заметно ускорилось...
Тогда я что-то так обрадывался и сделал сразу по 16 - получилось почему-то наоборот в два раза медленнее... :(
Есть ли способы рассчитать оптимальное количество..? Или тока мерять на практике можно?


Pavia ©   (20.03.09 04:08[115]


> Хм... Терминов "раскрутка цикла" и "развёртка цикла" раньше
> не встречал... Про их где-нибудь пишут в книгах?

Руководства по оптимизации от интел и амд подойдут?


> Пробовал сразу по 8 пикселов в цикле считать... Еле заметно
> ускорилось...

На моем процессоре придел достигнут 4.5тика.  1 тик на вычисление 0.5 на запись 3 байта 1.5*3=4.5 Остается мало вариантов для оптимизации только SSE и MMX. снизить число записей до 1 на два пикселя и совместить запись с рассчетами. А это уже прямая дорога в ассемблер.

Число портов для вычислений около 4 и еще 1 для записи чтения. Поэтому больше 4 не делают. 4 это рекоминдованное число.  Хотя порой бывают разные эффекты, так что практика иногда и расходится с теорией.


hotspot   (20.03.09 11:13[116]

Извините что чуть в сторону от темы, но ближе ничего пока не нашел..
Надо нарисовать порядка 10000 окружностей. TCanvas делает это (в зависимости от размера окружности) за 0,6 - 1,5 секунды. Можно ли вывод осужествить быстрее?
А то CAD, который секунду пытается прорисовать изображение при любом изменении объекта - эт перебор :(


ЮЮ ©   (20.03.09 11:56[117]


> Можно ли вывод осушествить быстрее?

Можно, если все 10000 окружностей не изменяют свое положение. Окружности, не перемещаемые в данный момент пользователем, должны быть просто фоном, а объектами становиться только когда с ними взаимодействуют.

Могу выслать небольшой проект 5-ти летней давности с подобной функциональностью.


hotspot   (20.03.09 12:08[118]

Буду очень благодарен. hotspot2006(собака)ya.ru


@!!ex ©   (20.03.09 13:30[119]

> [116] hotspot   (20.03.09 11:13)

редкий CAD рисует софтверно.


DomiNickDark   (20.03.09 13:44[120]

Интересный исходник от "Farbrausch" на Assembler'е:

Http://DomiNickDark.Narod.Ru/DemoScenes/Farbrausch/Demos/fr-0.1-source.txt

Никто не знает для какого он компилятора? (Tasm и Fasm не компилируют)


Вася   (22.03.09 22:35[121]

>>> При тестировании (на 1024х1024) сбоку слева недорисовывалась часть битмапа... Белая полоска получалась...
>>> Поменял "until x<=0;" на "until x<0;" - стало нормально... :)

DomiNick, Pavia, я правильно понял что в "Procedure Draw2_7;" желательно чтоб "Bitmap.Width" было кратно 4-м?
А то тогда снова та белая полоска сбоку появляется (даже при "until x<0;")...

Меня тут на одном форуме программистов научили считать время выполнения кода... Меряю время  вот так:

procedure TForm1.Button1Click(Sender: TObject);
var i, iTick: Integer;
begin
SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
iTick:=GetTickCount;
for i:=0 To 50 Do
   begin
   draw2_7;
   end;
form1.caption:=inttostr(GetTickCount-iTick);
SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_NORMAL);
end;

Правильно?

DomiNick, при
BitBlt(Form1.Canvas.Handle, 0, 0, 1024, 1024, Bitmap.Canvas.Handle, 0, 0, SrcCopy);
заместо
Form1.Canvas.Draw(0, 0, Bitmap);
это время как-то чаще "прыгает"... Но бывает и быстрее...

Посоветуйте как лучше...


Pavia ©   (23.03.09 13:07[122]


> желательно чтоб "Bitmap.Width" было кратно 4-м?

Обязательно. Если нужно можно переделать код вначале блоками по 4 потом то что в конце осталоь по 1-3.
На данный момент он хвост просто не будет обробатывать. Ничего страшного. За исключением случая Bitmap.Width <4


> Меня тут на одном форуме программистов научили считать время
> выполнения кода... Меряю время  вот так:

GetTickCount имеет не хорошую особенность. Его счетчик в среднем увеличивается раз в 16 мс и сразу на 16мс. те.
Вместо
01 02 03 04 ... 13 14 15 16 17 18 19 20 21 ... 31 32 33
Будет
00 00 00 00 ... 00 00 00 16 16 16 16 16 16 ... 16 32 32.
Так что время измерения должно привышать 16мс, а точнее что бы такая ошибка довала 1% нужно 1,6 секунды

А еще что-бы никто не перебивал нашу программу. Для этого ставим.
SetPriorityClass( GetCurrentProcess,REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_TIME_CRITICAL);

При этом гарантированное время без перебойной работы состовляет 4с. Потом идет перепланирование которое может передать управление другому процессу. Ничего страшного в этом нет. Но лучшии показатели будут в приделах 1-4с.

Я то мерию через
function RDTSC: Int64; register;
asm
RDTSC
end;

Но тут нюансов больше зато точнее. Можно более короткии промяжутки мерить. И быстрее. Давно хочу написать стать по измерению времени на компьюторе. Как только данных наберу побольше.


Вася   (24.03.09 04:46[123]

А насчёт "BitBlt(Form1.Canvas.Handle, 0, 0, 1024, 1024, Bitmap.Canvas.Handle, 0, 0, SrcCopy);" и "Form1.Canvas.Draw(0, 0, Bitmap);" ?
Что лучше и в чём разница?


Б   (24.03.09 08:21[124]

- BitBlt - быстрая функция блиттинга GDI, где последний флаг - режим блиттинга. Обычно SrcCopy - копирование.
- Canvas - это просто удобная обёртка под GDI-функции (См. исходники). Например, чтобы нарисовать линию нужно просто указать  цвет пера и координаты концов отрезка и не надо мучаться с созданием пера, получение контекста устройства, его выделением... и т.д.
Режим блиттинга устанавливается в CopyMode. (По умолчанию копирование).
Если нужно воспользоваться только блиттингом, то BitBlt - быстрее.
Есть ещё StretchBitBlt - только изображение уже масштабируется.


AutoBOT   (25.03.09 21:55[125]

BitBlt() - это функция из библиотеки GDI, Виндовоз через нее отрисовывает. Работает просто:

var DCs: HDC;
...
// контекст главной формы
DCs := GetDC(Form1.Handle);
// отрисовка в форму
BitBlt(DCs, 0, 0, Form1.Width, Form1.Height, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
// освобождаем контекст, убиваем
ReleaseDC(Form1.Handle, DCs);
DeleteDC(DCs);


Через BitBlt() готовый буферный кадр выводится прям на форму, 30 кадров в секунду обеспечивает всегда, у меня 64 кадра, ...скорость зависит от обработки в цикле...

P.S.
Кто знает, SetDIBitsToDevice() в реале быстрее отправит графические данные на форму чем BitBlt()? ...тесты что-то не показывают разницы, на моем компе одинаковая скорость...


antonn ©   (25.03.09 22:44[126]

обычно затык происходит не во время отображения буфера, а во время его формирования, bitblt очень быстрая вещь и искать быстрее смысла особого нет.


Вася   (27.03.09 14:02[127]

DoniNick, этот код для Nasm'а... ;)

>>> обычно затык происходит не во время отображения буфера, а во время его формирования, bitblt очень быстрая вещь и искать быстрее смысла особого нет

Так я же и говорю - на моём компе разницы по скорости между "BitBlt(...)" и "Canvas.Draw(...)" практически нету... :(
Может есть другие способы?

А "SetDIBitsToDevice(...)" у меня что-то непонятное требует... Как им пользоваться-то?


antonn ©   (27.03.09 22:47[128]


> Так я же и говорю - на моём компе разницы по скорости между
> "BitBlt(...)" и "Canvas.Draw(...)" практически нету... :
> (
> Может есть другие способы?

Так вот я и говорю - а зачем еще быстрее, если обычно бутылочное горлышко не в выводе битмапа на канву? :)

PS у канвы в реализации используется все тот же bitblt() (ну и для масштабирования аналогичная)


Вася   (28.03.09 00:53[129]

Мда?..

А помните я писал функцию для Делфи на Ассемблере для ускоренного вычисления синуса?..
Никто не разобрался как она работает и можно ли увеличить точность выдаваемого значения?..


DomiNickDark   (28.03.09 19:12[130]

> DoniNick, этот код для Nasm'а... ;)

О_О...

Пасибо.....

> Давно хочу написать стать по измерению времени на компьюторе.
>  Как только данных наберу побольше.


Pavia, когда это свершится дадите ссылку на статью..? ;)


DomiNickDark   (31.03.09 00:20[131]

>>>   >>> Даже если поставить Timer.Interval:=1; то он всё равно будет вызываться примерно раз в 55 миллисекунд, а не раз в 1
>>> Так и есть, хотя для некоторых случаев 18-20 FPS хватает.
>>> Если нужно быстрее - используй Application.OnIdle с Done = False (см. справку).

Справка на англицком... Не смог разобраться... :(
Делфи говорит неправильная процедура...

А кстати если таймер максимум "примерно раз в 55 миллисекунд, а не раз в 1", то как будет себя вести этот "Application.OnIdle с Done = False"?


@!!ex ©   (31.03.09 07:25[132]

> [131] DomiNickDark   (31.03.09 00:20)
> А кстати если таймер максимум "примерно раз в 55 миллисекунд,
> а не раз в 1", то как будет себя вести этот "Application.OnIdle
> с Done = False"?

Эти две вещи не связаны.
OnIdle - событие ничегонеделанья, не связано с таймером.


Xandr001   (31.03.09 08:03[133]

вот тут:

URL:: http://heanet.dl.sourceforge.net/sourceforge/graphics32/graphics32-1-8-3.7z
Размер:: 1,7 MБ (1 774 699 байт)

Быстрый канвас. где-то в примере про спрайты есть проект где используется ОнИдл. Вообще библиотека избавляет от многих "рисовальных" проблем.


Б   (31.03.09 15:14[134]


> Справка на англицком... Не смог разобраться... :(
> Делфи говорит неправильная процедура...


Например так:
1) Обработчик TApplicationEvents.OnIdle.
2) Типа такого:

Procedure TForm1.Idle(Sender: TObject; var Done: boolean);
begin
  // Анимация.
End;

Procedure TForm1.FormCreate(Sender: TObject);
begin
 Application.OnIdle:= Idle;
End;


P.S. Выводит быстрее таймера, даже не видно как воспроизводится анимация.


DomiNickDark   (31.03.09 21:06[135]

Благодарствую... Будем пробовать... :)

> Эти две вещи не связаны.
> OnIdle - событие ничегонеделанья, не связано с таймером.


А как тогда объясняется срабатывание быстрее таймера? И известно ли насколько быстрее?

З.Ы. Таймер умудряется работать как бы параллельно с основной прогой - он чтоли как бы отдельный поток для себя создаёт..?


Sapersky   (31.03.09 22:57[136]

OnIdle - событие ничегонеделанья, не связано с таймером.

На самом деле в TApplication.HandleMessage/ProcessMessage фактически аналог игрового цикла на PeekMessage:
If PeekMessage then <обработать> else OnIdle;
Если в OnIdle установить Done := True - Application "впадает в спячку" (WaitMessage), при Done := False будет крутиться постоянно.

А кстати если таймер максимум "примерно раз в 55 миллисекунд, а не раз в 1", то как будет себя вести этот "Application.OnIdle с Done = False"?

Крутиться с макс. доступной скоростью (и загрузкой процессора 100%), что обычно и требуется графическим демкам/играм. Правда, скорость анимации придётся подстраивать под текущий FPS.
Если хочется "притормозить" - можно поставить Sleep (имеет смысл ставить c интервалом кратным 10 мс, оно всё равно округляется).

З.Ы. Таймер умудряется работать как бы параллельно с основной прогой - он чтоли как бы отдельный поток для себя создаёт..?

Обычный - не создаёт (шлёт сообщения WM_TIMER). Создаёт мультимедиа-таймер (и поэтому ему доступны интервалы меньше чем 50 мс). Но по-моему проще OnIdle со Sleep.


Sapersky   (31.03.09 23:11[137]

Вообще есть способ повысить дискретность Sleep до 1 мс:
http://www.dtf.ru/articles/read.php?id=39888&page=2
но это, скажем так, способствует повышению общей тормознутости Windows, поскольку система будет в 10 раз чаще отвлекаться на системные задачи (читать в статье про quantum и прочее).


Б   (01.04.09 06:35[138]

2 Sapersky
> при Done := False будет крутиться постоянно.

У меня почему то, анимация через некоторое время останавливается. Почему?

> Если хочется "притормозить" - можно поставить Sleep

Я не использую Sleep, это как то тупо. Он простанавливает работу всего потока? Программы?
Лучше в OnIdle запоминайте системное время.


@!!ex ©   (01.04.09 09:48[139]

> [138] Б   (01.04.09 06:35)
> У меня почему то, анимация через некоторое время останавливается.
> Почему?

Код кривой.


> [138] Б   (01.04.09 06:35)
> Я не использую Sleep, это как то тупо. Он простанавливает
> работу всего потока? Программы?

НЕ тупо. Позволит одновременно контролировать скорость рендера и при этом не жрать 100% проц времени.
Останавливает работу потока в котором вызван.


Pavia ©   (01.04.09 15:58[140]


> Но по-моему проще OnIdle со Sleep

Мультимидийный таймер проще. 1мс. И не нужно заботиться.


> Вообще есть способ повысить дискретность Sleep до 1 мс:

Чуши не пишите. Sleep он гарантирует время задержки более но не менее указанного времени. Дискретность там не повышается. Там идея в том что если выставить максимальный приоритет у задачи то при вызови sleep(0) мы тут же поподаем в нашуже задачу только в другой поток. А гемора с планированием полно. Проще мультемидийный таймер там точность 1мс.


> Код кривой.

Согласен. Помниться когда только начинал разбираться умудрился написать код который на 300МГц работал быстрее чем на 2ГГц. =)в


@!!ex ©   (01.04.09 16:50[141]

> [140] Pavia ©   (01.04.09 15:58)
> Мультимидийный таймер проще. 1мс. И не нужно заботиться.

Многопточность - это проще? :)) Ну-ну.


Pavia ©   (01.04.09 18:15[142]


> Многопточность - это проще? :)) Ну-ну.

Так она там и там. Но там мы расчитываем каждую операцию, не дай бог дольше и будут проблемы. А тут все окей система сама прервет когда надо. И заботиться о всех проверках нужно меньше.


@!!ex ©   (01.04.09 18:41[143]

> [142] Pavia ©   (01.04.09 18:15)

OnIdle не создает второго потока.


Sapersky   (01.04.09 20:05[144]

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

См. фрагмент статьи начиная с "Поверье четвертое". О том, что timeBeginPeriod устанавливает размер кванта времени Windows, что влияет и на таймеры (MM/waitable), и на Sleep.

А тут все окей система сама прервет когда надо.

Это как, интересно, система может "прервать"? Если, допустим, выполняем в таймерной функции что-то более длительное чем интервал таймера...
ИМХО, может только прокрутить последующие итерации с меньшим интервалом, чтобы попытаться компенсировать "отставание".


Pavia ©   (01.04.09 20:33[145]


> См. фрагмент статьи начиная с "Поверье четвертое". О том,
>  что timeBeginPeriod устанавливает размер кванта времени
> Windows, что влияет и на таймеры (MM/waitable), и на Sleep.
>

А ты возьми и проверь не меняет она квант времени. Вернее на коких-то вариантах ос может и меняет, но на xp viste 2003 она не меняла. И вообще этот факт относиться к 2000.


Sapersky   (02.04.09 16:40[146]

Да, что-то не работает. Вроде же был эффект, правда, давно и на другом железе...
Sleep(1) занимает от 1.2 до 1.9 мс в зависимости от нагрузки. Подозреваю, что "довесок" сильно зависит от конкретного железа, надо будет проверить на старом компе.
MM-таймер как-то умудряется выдерживать интервал в 1 мс (хотя и не точно выдерживает, получается 0.9 с периодическими скачками до 2), что, конечно, круто, но... имеется неприятный побочный эффект: при превышении таймерного интервала (выполняем в таймерной функции что-то длительное) вся система начинает дико тормозить, даже 100% загрузка процессора не даёт такого эффекта. Так что "не дай бог дольше и будут проблемы" относится именно к MM-таймеру.


DomiNickDark   (02.04.09 19:38[147]

А можно перевести это всё на язык для простых смертных..? :)

"мультемидийный таймер" - это что за компонент и хде его добыть..? :)

И всё-таки как лучше и быстрее..?


@!!ex ©   (02.04.09 20:06[148]

> [147] DomiNickDark   (02.04.09 19:38)

MMSystem
help timeSetEvent

Быстрее OnIdle и QueryPerfomanceCounter


Pavia ©   (03.04.09 01:23[149]


> меется неприятный побочный эффект: при превышении таймерного
> интервала (выполняем в таймерной функции что-то длительное)
> вся система начинает дико тормозить, даже 100% загрузка
> процессора не даёт такого эффекта. Так что "не дай бог дольше
> и будут проблемы" относится именно к MM-таймеру.

Да, это следствие. Но некритично. Уменьшаем интервал динамически что бы успевал выполняться. Зато можем равномерно распеделить нагрузку на разные процессы. Если без него то все определяется самой медленной операцией что не есть хорошо. Нет такой гибкости в планировании.

QueryPerfomanceCounter высоко скоросной таймер. Особых нареканий нет. Единственное что в разных системах частота может быть любой, но постоянной и достаточно высокой блее 1МГц. И баг в многоядерных системах.

OnIdle и QueryPerfomanceCounter дают в суме, хороший результат.


@!!ex ©   (03.04.09 08:58[150]

> [149] Pavia ©   (03.04.09 01:23)
> QueryPerfomanceCounter высоко скоросной таймер. Особых нареканий
> нет. Единственное что в разных системах частота может быть
> любой, но постоянной и достаточно высокой блее 1МГц. И баг
> в многоядерных системах.

Чтобы бага не было , есть официальные заплатки.


Вася   (05.04.09 03:37[151]

Я-то с "OnIdle" давно разобрался (почти сразу, как посоветовали), а вот компонентов "QueryPerfomanceCounter" и "MMSystem" чтот никак не найду - на какой они должны быть вкладке? Может у меня Делфи старая?((

DomiNickDark, оно вот так работает:

В "public" надо дописать: "procedure Idle(Sender: TObject; var Done: Boolean);"

А в самом коде:

procedure Draw;
begin
// твоя процедура
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnIdle:=Idle;
end;

procedure TForm1.Idle(Sender: TObject; var Done: Boolean);
begin
Draw;
Done:=False;
end;


@!!ex ©   (05.04.09 05:58[152]

> а вот компонентов "QueryPerfomanceCounter" и "MMSystem"
> чтот никак не найду

А никто не говорил что это компоненты.

Help о них все знает и гугл тоже.


AutoBOT   (06.04.09 00:20[153]

> Pavia ©   (18.03.09 17:44) [107]

потрясающий код.. я его, пожалуй, стырю.. Х)
Pavia, вы не против?))


Sapersky   (06.04.09 15:48[154]

а вот компонентов "QueryPerfomanceCounter" и "MMSystem" чтот никак не найду

Вообще-то пример использования "компонента" QPC приводился ещё в [72]...
И, кстати, такой вариант теоретически должен нормально работать на двухъядерниках.


AutoBOT   (06.04.09 19:22[155]

Так там же что-то для замера времени.....

Или вы предлагаете как-то так:

While a=a Do
  Begin
  Draw2_7;
  Sleep(1);
  End;


не будет ли оно тормозить..?


@!!ex ©   (06.04.09 19:25[156]

> [155] AutoBOT   (06.04.09 19:22)

Постоянный рендер с расчетом времени между кадрами. Так делают ВСЕ большие игры. И ОЧЕНЬ много мелких. Так работают почти все демки.


Вася   (06.04.09 21:58[157]

>>> Постоянный рендер с расчетом времени между кадрами. Так делают ВСЕ большие игры. И ОЧЕНЬ много мелких. Так работают почти все демки.

Мда?? Ну я тогда попробую сделать так:

Stop: BooLean;
...
While Not Stop Do
 Begin
 Draw2_7;
 End;

У меня даже с OnIdle всё равно подвисает, может так лучше будет...)

А если сделать такой код в Form1.Button1Click - то его ж наверное не остановить...
Может это отдельным потоком делать, чтоб можно было как-то управлять рисованием?


@!!ex ©   (06.04.09 22:26[158]

> [157] Вася   (06.04.09 21:58)

Ну лично я в таких случаях просто не использую форм, а пишу окно на API. Там таких проблем нет.
Остановить цикл в кнопке можно, если в цикл поместить Application.ProcessMessages(), но это убьет напрочь производительность.


@!!ex ©   (06.04.09 22:26[159]

Кстати, для окон с формами есть простое решение:
OnPaint:
begin
 //Draw Frame
 InvalidateRect(Handle,nil,false);
end;


Вася   (06.04.09 23:01[160]

>>> Ну лично я в таких случаях просто не использую форм, а пишу окно на API. Там таких проблем нет.

А как там тогда? Примерчика не будет? ;)


Б   (07.04.09 05:10[161]


> Вася   (06.04.09 23:01) [160]


> А как там тогда? Примерчика не будет? ;)


http://www.mirgames.ru/articles/base/pathfind.html


AutoBOT   (20.04.09 01:19[162]

Почитал... Подумал...

> Вася   (03.03.09 20:28) [71]
>
> У меня случайное изображение...


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


AutoBOT   (20.04.09 01:53[163]

А тема так и застопорилась..? Ещё быстрее и оптимальнее невозможно уже чтоли? :)
Да и обещанной статьи про "измерения" не видно... :(

Кстати... А как создавать и выводить полупрозрачные битмапы??


Б   (20.04.09 09:08[164]

> Кстати... А как создавать и выводить полупрозрачные битмапы??

Windows.AlphaBlend;


antonn ©   (20.04.09 09:19[165]

выводить на чем?


AutoBOT   (21.04.09 01:03[166]


> Windows.AlphaBlend;


Благодарю... :)

Начал потихоньку разбираться с ним, но получается выводить только на форму... :(
В Image1, например, не хочет нарисовываться... :(


Вася   (03.05.09 23:19[167]

Я кое-что подкоректировал и вроде уже нормально заработало...)
Хотя на старых компах ещё подтормаживает...

Спасибо всем!)

>>> @!!ex ©   (02.03.09 00:00) [59]
>>> у меня 1680х1050 фуллскрин несколько обработок всех пикселей всего экрана(и там далеко не только вычисление синуса) не тормозит...
>>> а почему? А потому что пиксели экрана эта та штука, которую надо считать на видухе, а не на ЦПУ.

То есть выполнять код можно заставить не основной процессор а видеокартовский?
А как это сделать? Умеет ли он считать синусы?)))


@!!ex ©   (04.05.09 07:46[168]

> [167] Вася   (03.05.09 23:19)
> А как это сделать?

Гугли "шейдеры". Я GLSL предпочитаю.


> [167] Вася   (03.05.09 23:19)
> Умеет ли он считать синусы?)))

И не только синусы.


@!!ex ©   (04.05.09 08:14[169]

> [168] @!!ex ©   (04.05.09 07:46)

http://sol-online.org/index.php?content=info&project=shaderconfig


Вася   (04.05.09 16:57[170]

"GLSL" поищу, спасибо... :)

"Shader Config" интересная штука, но русской что-то нету на сервере, а в английской превью не работает... Размазня какая-то получается... :(


@!!ex ©   (04.05.09 17:34[171]

> [170] Вася   (04.05.09 16:57)
> в английской превью не работает... Размазня какая-то получается...
> :(

Поподробнее?


@!!ex ©   (04.05.09 18:11[172]

> русской что-то нету на сервере

там есть русский туториал, может поможет


Вася   (05.05.09 01:38[173]

>>> Поподробнее?

А вы случайно не один из разработчиков? ;)
Так интересуетесь, как своей программой... :))

По большему счёту просто чёрный экран...
А иногда какие-то беспорядочные фигуры... :(

Прям как на старой приставке Денди, если картридж не до упора вставить......


И ещё с ярлыками небольшой баг (или как там оно называется), но с ними я уже разобрался... :)


@!!ex ©   (05.05.09 15:44[174]

> [173] Вася   (05.05.09 01:38)
> А вы случайно не один из разработчиков? ;)

Таки да. :)


Вася   (05.05.09 22:28[175]

>>> Таки да. :)

:)

Там в "Свойствах" ярлыков на "Рабочем Столе" и "Быстром Запуске" не проставлена "Рабочая папка", отчего программа какие-то файлы не могла найти... *


@!!ex ©   (05.05.09 22:39[176]

> [175] Вася   (05.05.09 22:28)

tutorial смотрели? Помогло?


Вася   (05.05.09 23:58[177]

С ярлыками-то я сам разобрался... А вот превью не пашет... Наверное из-за железа, я думаю...

В выходные попробую на другом компе запустить, у знакомых...


@!!ex ©   (06.05.09 00:15[178]

> [177] Вася   (05.05.09 23:58)

Там есть Mesa OpenGL Driver, пахать должно даже на виртуальных машинах.


DomiNickDark   (14.05.09 02:25[179]

Хм... Тема зависла? :)

Больше ни у кого нету идей "ускорения"..? ;)


CSS   (17.06.09 17:32[180]

Удалено модератором
Примечание: Задай вопрос в своей ветке


имя   (16.07.09 09:35[181]

Удалено модератором


DomiNickDark   (18.07.09 21:24[182]

А может просто создать массив указателей? Так не быстрее будет..?
Ну или двухмерную матрицу указателей...

Сейчас попробую так сделать и посмотрю что будет со скоростью... :)


CSS   (31.07.09 19:19[183]

Удалено модератором


Beermonza ©   (02.08.09 19:16[184]

Товарищ AutoBOT, не забывайте, что бездумно копируя мои фразы с форума programmersforum.ru вы нарушаете авторские права.

>> AutoBOT   (25.03.09 21:55) [125]

>> BitBlt() - это функция из библиотеки GDI, Виндовоз через нее отрисовывает. >> Работает просто:

>> var DCs: HDC;
>> ...
>> // контекст главной формы
>> DCs := GetDC(Form1.Handle);
>> // отрисовка в форму
>> BitBlt(DCs, 0, 0, Form1.Width, Form1.Height, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
>> // освобождаем контекст, убиваем
>> ReleaseDC(Form1.Handle, DCs);
>> DeleteDC(DCs);
Это мой пост 19 http://www.programmersforum.ru/showthread.php?t=38106&page=2

>> Через BitBlt() готовый буферный кадр выводится прям на форму, 30 кадров
>> в секунду обеспечивает всегда, у меня 64 кадра, ...скорость зависит от
>> обработки в цикле...
Это мой пост 17 http://www.programmersforum.ru/showthread.php?t=38106&page=2

>> P.S.
>> Кто знает, SetDIBitsToDevice() в реале быстрее отправит графические
>> данные на форму чем BitBlt()? ...тесты что-то не показывают разницы, на
>> моем компе одинаковая скорость...
Это мой пост 648 http://programmersforum.ru/showthread.php?t=338&page=65

Если вам нечего сказать, то не надо выдавать чужие посты за свои, ...указывайте источник.


@!!ex ©   (02.08.09 19:21[185]

Удалено модератором


Beermonza ©   (02.08.09 19:23[186]

Удалено модератором


@!!ex ©   (02.08.09 19:45[187]

> [186] Beermonza ©   (02.08.09 19:23)

Я бы с вами согласился, будь это публикация.
Но это форум. И обижаться, что кто-то не поставил копирайт, не имеет смысла.
Тем более с таким адским некропостингом. АвтоБОТ наверняка уже не посещает эту конференцию, а сообщения эти все уже забыли.


Beermonza ©   (02.08.09 20:44[188]

Если все будут молчать, то так и будет продолжаться все время. Просто этот несознательный человек выдал все мои мысли от себя, по закону это уже воровство, ...мог бы перефразировать хотя бы, на худой конец. А раз так, то нужно воспользоваться тегом "Цитата", все должны это помнить, всегда. Код - пожалуйста, можно указывать без автора. Это не первый случай.


@!!ex ©   (02.08.09 21:14[189]

Удалено модератором


antonn ©   (02.08.09 23:47[190]

Удалено модератором


antonn ©   (02.08.09 23:59[191]

я даже больше скажу, вот тут куски моего кода, и ниразу не под авторством, и что мне теперь идти ругаться?
http://programmersforum.ru/showpost.php?p=62147&postcount=12


Beermonza ©   (03.08.09 16:14[192]

Однако, у всех после ника показан значок, к чему бы это?
Дело не в том, ваш код или не ваш, вы делитесь кодом, раз показываете его, я тоже делюсь кодом и всегда говорю, что он доступен всем, ...но в моем случае, человек создал сообщение из моих мыслей и фраз, причем целиком, и говорит их от своего имени, не знаю что он хотел этим заслужить, или может показаться умнее, т.е. попугай, по русски, извините за сравнение. Вот если я сейчас возьму чей-то умный пост и напишу его слово в слово на другом форуме, будет считаться что это мой, никто ведь не знает. Я не жадный, мне из принципа обидно. На форумах часто говорят цитатами из книг, мы иногда это замечаем и ставим на место тех, кто так поступает, ...если человеку есть что сказать, он пишет, ...я против любого выдергивания, тем более против откровенного копирования под своим именем, пользователи должны соблюдать хотя бы элементарные правила, даже прописанные в специальном разделе, хотя бы заключить все в тэг "Цитата". Я всегда если вижу что-то интересное, беру все в цитату и подписываю сверху, например: "а вот некто интересную мысль предложил", ...ну что, это так тяжело сделать? ....или теперь можно прикрыться, мол что "это была пародия"? Ко всем присутствующим нет никаких претензий, кроме того несознательного пользователя. Давайте не будем закрывать на это глаза и бороться с этим, я начал с себя, и другим там поступать не дам, и говорить об этом буду всем и каждому.
Извините за ОФФ.

А по теме если, то, есть методы быстрее, гораздо быстрее.


@!!ex ©   (03.08.09 20:11[193]

Удалено модератором


Beermonza ©   (03.08.09 23:45[194]

Удалено модератором


antonn ©   (04.08.09 02:15[195]


> Однако, у всех после ника показан значок, к чему бы это?

тут это означает, что пользователь зарегистрирован. Почему был избран именно этот символ мне все равно, не я писал форум.


> Дело не в том, ваш код или не ваш, вы делитесь кодом, раз
> показываете его, я тоже делюсь кодом и всегда говорю, что
> он доступен всем, ...но в моем случае, человек создал сообщение
> из моих мыслей и фраз, причем целиком, и говорит их от своего
> имени, не знаю что он хотел этим заслужить, или может показаться
> умнее, т.е. попугай, по русски, извините за сравнение.

от произнесенного лично у меня восхищения не появилось :)


> А по теме если, то, есть методы быстрее, гораздо быстрее.

конечно есть, только не все будут делиться кодом :)
например тут бенчмарк части моих наработок, если интересно http://desksoft.ru/index.php?downloads=attachments&id=103 (576кб, zip).
Во всех тестах "draw scene" на сцену 512*512 выводится 4ре текстуры 256*256, каждая с маской-бампом. Плюс если есть - маски-освещение, плюс "обычный битмап" поверх (лого дельфи). Ессно все 32 битное, с альфаканалом.  В "шарпе" ко всему добавляется эффект "sharpen" с "дальностью" 3 пикселя.
В остальных тестах на битмап 512*512 выводится другой битмап 512*512 в координаты 10,10 (т.е. выводимая область 502*502). Тоже все 32 битные. В зависимости от теста они либо просто копируются, с альфой, с "прозрачным цветом" и тп.


antonn ©   (04.08.09 02:17[196]


> например тут бенчмарк части моих наработок, если интересно

цифирки в результатах теста - fps


CSS   (04.08.09 17:34[197]

antonn, а оно сделано без всяких OpenGL и DirectX'ов?

А то что-то не очень верится... Слишком уж впечатляюще выглядит всё... ^__^

Научите как так делать? =)


antonn ©   (04.08.09 18:32[198]

сделано софтваре, много стырено у spriteutils и fastlib, бенчмарк древний и местами неоптимальный, ничего не покажу :)
собственно многим хватит и fastlib у них и примеры есть нормальные


Beermonza ©   (06.08.09 18:55[199]


> от произнесенного лично у меня восхищения не появилось :
> )

Дык, никаких восхищений и быть не должно, ...должно быть отвращение, к типу людей, копирующих чужие высказывания/сообщений, либо от своей лени написать самому, либо от нечего сказать, но мулька )

Хм, а я рисую на битмапе 1136x781x24 в 5 слоев перенося подложку в буфер, затем объекты, довольно крупные 455х500 штук 10 в кадре с альфа-каналом и анимацией в 24 кадра в секунду, ...все это рисует максимум 100 fps, вывод в форму GDI, обработка в памяти на ассемблере плюс MMX. Специально ограничиваю 25 fps, просто никчему отрисовывать лишний раз, только по изменению анимации. У меня все шевелится, так что перерисовывается все. Если интересно, поделюсь или ссылку дам на "разбор полетов", если не возбраняется давать ссылки на иной форум.


CSS   (06.08.09 19:07[200]

А у Вас не бывает ошибки "Canvas does not allow drawing." ? Как с ней бороться?
Чем быстрее я пытаюсь делать вывод на форму тем больше и больше их выскакивает... =((

> Beermonza ©   (06.08.09 18:55) [199]

Было бы интересно... =)


Beermonza ©   (06.08.09 20:53[201]

Для начала вывод GDI, ...все знакомы уже ))

Var
 DCs: HDC;
...
DCs := GetDC(Form1.Handle);
BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
ReleaseDC(Form1.Handle, DCs);
DeleteDC(DCs);


...если на экран, то так:

Var
 DCs: HDC;
...
DCs := GetDC(0);
BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
ReleaseDC(0, DCs);
DeleteDC(DCs);


X, Y - координаты начала отрисовки;
W, H - габариты изображения;
{битмап} - картинка, в указанном формате.

Теперь как задать битмапы. По идее нужно два по размеру зоны отрисовки, первый - невидимый кадр, что потом выводится на экран, второй - статическая подложка, ...в играх используется как поверхность некоторой игровой карты. Чтобы быстро рисовать нужно двойной доступ к битмапам, как стандартный, в котором можно применить Canvas, так и через указатель на данный в памяти. Это способ через CreateDIBSection():

Var
 BInfo: tagBITMAPINFO;
 PointerBuf: Pointer;
 BufScr: PChar;
 BufLine: Integer;
...
BInfo.bmiHeader.biSize := SizeOf(tagBITMAPINFOHEADER);
BInfo.bmiHeader.biWidth := W;         // длина буфера
BInfo.bmiHeader.biHeight := H;         // высота буфера
BInfo.bmiHeader.biPlanes := 1;         // как хранить данные (-1 - переворачивает)
BInfo.bmiHeader.biBitCount := 24;    // глубина цвета (3 байта, R,G,B)
BInfo.bmiHeader.biCompression := BI_RGB;

// создается буфер
Buf := TBitmap.Create();
Buf.Handle := CreateDIBSection(Canvas.Handle, BInfo, DIB_RGB_COLORS, Pointer(BufScr),0,0);
PointerBuf := Pointer(BufScr);
// длина линии буфера в байтах
BufLine:=W*3;
// нужно для быстрой и безошибочной работы алгоритма на ассемблере
If BufLine mod 4 <> 0 then BufLine:=((BufLine div 4)+1)*4;


А если проще, то вот так:

GetMem(BufScr, H*W*3);
PointerBuf := Pointer(BufScr);
BufLine:=W*3;
If BufLine mod 4 <> 0 then BufLine:=((BufLine div 4)+1)*4;


В любой момент заполнить массив буфера можно вот так, правда не быстро, но при возможности:
// залить черным
FillChar(BufScr^, W*H*3, 0);


Теперь трюки. Допустим у нас есть подложка Back и буфер Buf, полный размер буфера известен BufLength := (H*W*3) div 8; - для ровного счета. Указатели мы получили в начале создания. Вот так быстро переносим одно изображение в другое:

 asm
   push esi
   push edx

   mov ecx, BufLength
   mov esi, PointerBack
   mov edx, PointerBuf

 @@mix:
   movq      xmm0, [esi]     // Back -> в регистр
   movq      [edx], xmm0     // Buf <- из регистра

   add esi, 8
   add edx, 8

   loop @@mix

   pop edx
   pop esi

   emms
 end;


Остальное попробую сначала упростить, потом покажу. Пример работы показать не могу, ибо это игра, делается еще. Вы можете сами проверить без проблем.


Beermonza ©   (06.08.09 22:03[202]

Вот так рисуем в памяти на буфере кадра, ...это для целого изображения спрайта, без обрезки:

type
 TRGB = packed record
   R: Byte;
   B: Byte;
   G: Byte;
 end;

 PRGB = ^TRGB;

Var
 C, yy: Integer;
 Bits, MapBits: PChar;
 TexLine: Integer;
 TexPoint, MapPoint, BufPoint: PChar;
 TexPixel, MapPixel, BufPixel: PRGB;

const C1: int64 = $FFFFFFFFFFFFFFFF;

SW := {длина спрайта};
SH := {высота спрайта};

// определим нужно ли отрисовывать спрайт (это часть алгоритма обрезки, тут не показываю)
C := ((SW+1)*3) div 8;
If C > 0 then
 Begin
   // массивы изображения, текстуры, маски, и буфера куда отрисовываем
   Bits    := {массив текстуры};
   MapBits := {массив маски};
   TexLine := {длина строки в файтах};

   // координаты в буфере (это должны быть динамические данные)
   X := 10;
   Y := 10;

   // Указатель на певую строку текстуры, маски и фона
   TexPoint  := Bits;
   MapPoint  := MapBits;
   BufPoint  := BufScr + (H - 1 - X) * BufLine + Y * 3;    //формат 24 бита, 3 байта на пиксел

   asm // подготовка маски
     pxor      xmm7, xmm7
     movq      xmm3, C1
     PUNPCKLBW xmm3, xmm7
   end;
   
   // цикл по количеству строк в изображении спрайта
   For yy:=0 to SH-1 do
     Begin
       TexPixel := PRGB(TexPoint);
       MapPixel := PRGB(MapPoint);
       BufPixel := PRGB(BufPoint);

       asm
         push edi
         push esi
         push edx
         push ecx

         mov ecx, C
         mov esi, [TexPixel]
         mov edx, [BufPixel]
         mov edi, [MapPixel]

       @@1:
         // это алгоритм отброса пикселей с полной прозрачностью
         cmp dword ptr [edi], 0
         jne @@mix
         cmp dword ptr [edi+4], 0
         je  @@Next

       @@mix:
         // смешивание
         movq      xmm0, [esi]     // tex
         PUNPCKLBW xmm0, xmm7      // convert to word

         movq      xmm1, [edx]     // Buf
         PUNPCKLBW xmm1, xmm7
         psubw     xmm0, xmm1      // tex-Buf

         movq      xmm2, [edi]     // map
         PUNPCKLBW xmm2, xmm7

         pmullw    xmm0, xmm2      // (tex-Buf)*map
         psrlw     xmm0, 8         // shr 8
         paddw     xmm1, xmm0      // zone + (tex-Buf)*map shr 8

         pand      xmm1, xmm3
         packuswb  xmm1, xmm1      // convert to byte

         movq      [edx], xmm1

       @@next:
         add esi, 8
         add edx, 8
         add edi, 8
         loop @@1

         pop ecx
         pop edx
         pop esi
         pop edi
       end;
       
       // перемещение на следующую строку в изображении
       TexPoint := TexPoint + TexLine;
       MapPoint := MapPoint + TexLine;
       BufPoint := BufPoint - BufLine;
     end;

   asm
     emms
   end;

 end;


Рисует ООЧЕНЬ быстро. Теперь момент, как и что за текстуры я использую и загружаю. В основном это PNG-файлы, ...полное сохранение цветов, альфа-канал и весят сравнительно мало. Вот так это происходит:

uses
 PNGImage; // отличная библиотека, советую поискать
 ...

type
 BGR = packed record
   B: Byte;
   G: Byte;
   R: Byte;
 end;

 TBGR = array [word] of BGR;

Var
 PNGimg: TPNGObject;
 y: Integer;
 i, j: Word;
 Bits: ^TBGR;
 Alpha: PByteArray;
 TexBits, MapBits: PChar;
 ...

 // загрузка PNG-файла
 PNGimg := TPNGObject.Create;
 PNGimg.LoadFromFile({путь к файлу});
 ...

 // заполняем массив текстуры и маски спрайта
 For i := 0 to PNGimg.Height - 1 do
   Begin
     Bits := PNGimg.Scanline[i];
     Alpha := PNGimg.AlphaScanline[i];

     For j := 0 to PNGimg.Width - 1 do
       Begin
         y := j*3 + (i*(PNGimg.Width*3));  //24 бита, формула позиционирования в одномерном массиве

         TexBits[y]     := Chr(Bits[j].B);
         TexBits[y + 1] := Chr(Bits[j].G);
         TexBits[y + 2] := Chr(Bits[j].R);

         MapBits[y]     := Chr(Alpha[j]);
         MapBits[y + 1] := Chr(Alpha[j]);
         MapBits[y + 2] := Chr(Alpha[j]);
       end;
   end;


TexBits и MapBits заполняются параллельно, и как видно, на первый взгляд, MapBits не рационально большой, хотя в исходном варианте в PNG он в 3 раза меньше по объему, ...но, это, только вещь кажущаяся ))) ...в отрисовке на ассемблере с MMX очень важно, чтобы данные шли параллельно, тогда легко забирая и обрабатывая по 8 байт скорость отрисовки увеличивается, нежели при расчете 3-х байт текстуры и 1-го байта маски. Есть еще один плюс такого увеличения массива маски, у нас есть независимое управление альфа-каналом по его трем составляющим R, G и B, т.е. можно, например, указать прозрачным какой-то один цвет а остальные оставить не прозрачными, в общем, варианты все, которые существуют.

Надеюсь нет ошибок, упрощал без проверки, извините, если сразу не заработает, придется изучить и покопаться.


antonn ©   (06.08.09 22:16[203]

такой ерундой мы тоже занимались: http://www.delphimaster.ru/cgi-bin/forum.pl?id=1200150296&n=7

PS я хз сколько ужрет у меня проца полноэкранное формирование кадра (тоже игру пишу :) ), просто там бамп, лайтмапы (причем они так же 32 битные), если надо рефракция (обычно типа колыхания водной поверхности, но тормозит нещадно в больших размерах).


Beermonza ©   (06.08.09 22:22[204]

У меня на Core 2 Duo 1,8GHz моя нещадно-огромная сцена ворочиется максимум на 30-40% загрузки CPU и 25 fps, и это еще не победа, работы ведутся.


Beermonza ©   (06.08.09 22:39[205]

На счет копирования одного изображения в другое, по одному размеру обоих, то я быстрее алгоритма, что показал, не придумал еще, ...особенно, когда идет массивный цикл сбора кадра, время копирования подложек ощутимо влияет на скорость общего вывода.
А отрисовка не самая идеальная, ...нужно подумать, отправить за циклы всю статику, или полустатику, пока нет времени этим заниматься. Но и так уже кое-что ))

Кстати, antonn, а что за формула для линзы применена, ...все искал, как-то не попал на то, от чего оттолкнуться. Заметил формулу, по которой я смешиваю? ...result := buf + (tex-buf)*map shr 8 и по каждой компоненте цвета, грубовато для линзы?


CSS   (06.08.09 23:16[206]

> uses
>  PNGImage; // отличная библиотека, советую поискать


Поискал в поисковике...
Часть ссылок дохлая, а остальные не устанавливаются в мою Делфи 7...

Где-нибудь есть офф.сайт у него (а то может мне просто какую-то фигню подсунули)? =))


antonn ©   (07.08.09 00:01[207]


> Beermonza ©   (06.08.09 22:39) [205]

у меня для линзы в бенчмарке маска, делал по примеру фастлиба :)


> CSS   (06.08.09 23:16) [206]

просто скачай, и не устанавливай, просто подключай модули, вот тут типа пример перегона в Tbitmap c альфой:
http://forum.vingrad.ru/forum/topic-267153/kw-pngimage.html


Beermonza ©   (07.08.09 00:17[208]


> antonn ©   (07.08.09 00:01) [207]
> у меня для линзы в бенчмарке маска, делал по примеру фастлиба :)

Переведи )) ...алгоритм посмотреть можно? ...ссылочку? ...я на откровенный гемор натыкаюсь с матрицами, или у тебя тоже так?


antonn ©   (07.08.09 01:22[209]

ну вот сам фаст_либ с примерами http://desksoft.ru/index.php?downloads=files&id=90


antonn ©   (07.08.09 01:22[210]

Правда это все таки не совсем линза, но похоже :)


Beermonza ©   (07.08.09 15:36[211]

Хорошо, спасибо, посмотрю.


имя   (07.08.09 17:02[212]

Удалено модератором


CSS   (16.08.09 05:20[213]

Beermonza, а всегда нужно делать так:

//на форму
DCs:=GetDC(Form1.Handle);
BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
ReleaseDC(Form1.Handle, DCs);
DeleteDC(DCs);

//на экран

DCs:=GetDC(0);
BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
ReleaseDC(0, DCs);
DeleteDC(DCs);


Я всегда так делал:

BitBlt(Form1.Handle, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
или так:
BitBlt({битмап}.Canvas.Handle, 0, 0, W, H, GetDC(0), X, Y, SRCCOPY);

Это хуже?



А который ассемблер используется в Делфи? Tasm, Masm или какой-то свой?
Я нигде не могу найти информацию по применению именно ассемблерных вставок для Делфи, а не просто по трансляторам...
И не найдётся ли что-нибудь про этот MMX чтоб для начинающих было? Очень хочется разобраться в Ваших примерах... =)

> очень важно, чтобы данные шли параллельно, тогда легко забирая
> и обрабатывая по 8 байт скорость отрисовки увеличивается,
>  нежели при расчете 3-х байт текстуры и 1-го байта маски.


Может "по 6 байт" или я чего-то не понял? =(


А как может быть "прозрачным какой-то один цвет" я даже представить не могу... =)


antonn ©   (16.08.09 11:21[214]


> Может "по 6 байт" или я чего-то не понял? =(

там все равно выравнивание будет, до 4х байт, к тому же битмап может быть с альфаканалом и как раз 4 байта на пиксель - ARGB.

прозрачный цвет - transparentcolor, это св-во у TImage например :)


CSS   (16.08.09 13:22[215]

> antonn ©   (16.08.09 11:21) [214]

Да я про 202-й пост, предпоследний абзац (в самом конце)... =)


antonn ©   (16.08.09 15:25[216]

ну два пикселя разом, видимо :)


Beermonza ©   (19.08.09 23:46[217]

> CSS © (16.08.09 05:20) [213]
> Beermonza, а всегда нужно делать так:

> //на форму
> DCs:=GetDC(Form1.Handle);
> BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);
> ReleaseDC(Form1.Handle, DCs);
> DeleteDC(DCs);

Нет, не всегда. Это общее понятие о контексте формы и его использование. Нам нужен быстрый доступ, вот мы и получаем контекст устройства и храним его, зачем каждый раз делать одни и те же не нужные действия. Я беру контекст в OnCreate формы:

DCs:=GetDC(Form1.Handle);

... освобождаю его в OnDestroy формы:

ReleaseDC(Form1.Handle, DCs);
DeleteDC(DCs);


...сам BitBlt в конце процедуры построения кадра:

BitBlt(DCs, X, Y, W, H, {битмап}.Canvas.Handle, 0, 0, SRCCOPY);

> CSS © (16.08.09 05:20) [213]
> А который ассемблер используется в Делфи? Tasm, Masm или какой-то свой?
> Я нигде не могу найти информацию по применению именно ассемблерных
> вставок для Делфи, а не просто по трансляторам...
> И не найдётся ли что-нибудь про этот MMX чтоб для начинающих было?
> Очень хочется разобраться в Ваших примерах... =)

Классический, Tasm не поддерживается. По MMX вот тут есть немного: http://www.gamedev.ru/code/articles/?id=4272
Примеры не мои, они собраны по описаниям, оптимизированы из кусков, и помогали мне в "поисках правды", в свое время, хорошие люди, за что им спасибо.

> CSS © (16.08.09 05:20) [213]
> Может "по 6 байт" или я чего-то не понял? =(

В MMX-технологии фишка в том, что процессор с ее поддержкой имеет 8 дополнительных 64-разрядных регистра, обычные регистры - 32-разрядные, ...т.е. мы можем ворочить сразу по 8 байт информации, вместо стандартных 4-й, ...от это значительный прирост производительности кода, при обработке параллельных массивов. Мы специально проверяем наши загруженные текстуры на предмет деления строки пикселей на 4, чтобы задать длину таким образом, чтобы было как можно меньше лишних байт, если длина окажется не четной, ...ведь работать нам с текстурами 24-битными - это по 3 байта на пиксел, альфа-канала тут нет, он отдельно. Давайте покажу структурно.

Вот так идут данные в массиве PChar:
это наши 8 пикселей изображения, тут 24 байта.
BGR BGR BGR BGR BGR BGR BGR BGR

а вот так берет эти же данные код на ассемблере
BGRBGRBG RBGRBGRB GRBGRBGR - это текстура
BGRBGRBG RBGRBGRB GRBGRBGR - это альфа-канал
BGRBGRBG RBGRBGRB GRBGRBGR - это задний фон

...т.е. за 3 цикла он обработал по формуле смешивания 8 пикселей и наложил их на задний фон. Этот метод в 6 раз производительнее метода со сканированием ScanLine, судя по загрузке CPU.

> CSS © (16.08.09 05:20) [213]
> А как может быть "прозрачным какой-то один цвет" я даже представить
> не могу... =)

В FotoShop доводилось работать? ...в принципе это явление, когда в текстуре просвечивается только определенный тон, или все, или по выставленным уровням, эффект вычитания. Например, у вас есть текстура, полупрозрачная, значит в исходном варианте, например в PNG, 1 пиксел альфа-канала это 1 байт, ...а у нас альфа-канал - RGB, ...значит можно задать например врагмент текстуры с прозрачность не 100 100 100, а 50 100 100, в этом случае, фрагмент будет не только полупрозрачный, но и будет иной цвет прозрачности, т.е. этот альфа-канал просвечивает разные цвета по-разному. Если указать 0 100 100, то все красные тона не будет видно, а остальные останутся полупрозрачными, и т.д. и т.п. Разумеется, нужно подготавливать альфа-канал заранее, или как я показал, просто выдергивать его из PNG и разбрасывать на 3 составляющие, последующие эффекты в специальных кодах, матрицах, шаблонах, через которые пропускается массив альфа-канала.


Beermonza ©   (20.08.09 00:01[218]

Извините, увлекся, PhotoShop конечно же.


antonn ©   (20.08.09 00:34[219]


> Этот метод в 6 раз производительнее метода со сканированием
> ScanLine, судя по загрузке CPU.
>

это если последовательно перебирать строки, в случае с поворотами там разница раз в 20 будет точно :)


Beermonza ©   (20.08.09 15:49[220]

> antonn ©   (20.08.09 00:34) [219]
> это если последовательно перебирать строки, в случае с поворотами там разница раз в 20 будет точно :)

Ой, и не говорите :) ...это просто зверь софтварный.


antonn ©   (20.08.09 16:36[221]

Вот тут ставили тесты с поворотами: http://forum.vingrad.ru/forum/topic-241113/anchor-entry1734947/0.html
canvas.pixel - 20,66 сек, fps ~5
scanline - 5,43 сек, fps ~18
"массив" - 0,26 сек (с выводом в tbitmap в каждом кадре 0,28-0,29), fps~384

массив - даже без оптимизаций, тот же код что и со scanline, просто "пиксели" заменены на массив, разница в 20 раз =)


Sapersky   (20.08.09 19:29[222]

Ну сделайте себе копию сканлайнов в массив array of PRGBArray, чтобы обращаться к ним без вызова функции. Должно быть ещё быстрее, т.к. лишних копирований нет.
Про библиотеку с изначально "правильным" сканлайном я уж молчу.


Beermonza ©   (21.08.09 00:08[223]

PChar быстрее, я проверял все варианты. С ним можно работать на указателях, что, собственно, и показал в примерах, ...загоняем подряд, берем по указателю на ячейку памяти.


Sapersky   (21.08.09 13:30[224]

А сканлайн что такое, не указатель? Проблема в том, что у TBitmap получение сканлайна сделано, мягко говоря, неоптимально (см. [99]).


Beermonza ©   (21.08.09 16:58[225]

> Sapersky   (21.08.09 13:30) [224]
> А сканлайн что такое, не указатель? Проблема в том, что у TBitmap получение
> сканлайна сделано, мягко говоря, неоптимально (см. [99]).

Я про применение иного типа массива.

> Ну сделайте себе копию сканлайнов в массив array of PRGBArray

А можно ли так же элегантно и быстро "прыгать" по данным как с массивом PChar, просто прибавляя число, соответствующее длине строки?
TexPoint := TexPoint + TexLine;

В этой строчке все, что нужно, без лишних затрат.


Sapersky   (21.08.09 17:55[226]

А можно ли так же элегантно и быстро "прыгать" по данным как с массивом PChar, просто прибавляя число, соответствующее длине строки?

См. пример [97].
В общем случае ширина строки в битмапе не обязательно равна Width * BytesPP, она округляется до 4 байт, т.е. в конце строки может быть "хвост". Поэтому в начале вычисляется "шаг" между строками dx (данные + возможный "хвост"). И уже с помощью этого шага автор "прыгает" по картинке.
Если у вас всё 32-битное - можно не заморачиваться с "хвостами", ширина уже кратна 4-м.
Разве что с верхом-низом может быть путаница, но это решаемо, во всяком случае мне не сильно мешает.


@!!ex ©   (21.08.09 18:31[227]

> [225] Beermonza ©   (21.08.09 16:58)
> А можно ли так же элегантно и быстро "прыгать" по данным
> как с массивом PChar, просто прибавляя число, соответствующее
> длине строки?
> TexPoint := TexPoint + TexLine;

А что мешает?


Beermonza ©   (21.08.09 23:55[228]

> @!!ex ©   (21.08.09 18:31) [227]
> А что мешает?

Вот это безобразие )))
Inc(DWord(Pixels), dx);

Еще в коде должна быть обрезка, там множество условий, и если в ней тянутся такие перлы преобразований, то смысл искать слабое "место" теряется, ...все места кода должны быть "сильными".

Я лично себе задал четко вопрос: "мне нужна скорость или не нужна?" , нужна, ...посему не стану делать действия ради действий, иначе какой смысл во всех этих выскребаниях хотя бы 2% прироста скорости кода.

Самый быстрый способ в памяти я показал выше, вообще без всего этого поползновения со ScanLine и шагания по строкам.


antonn ©   (22.08.09 00:01[229]

попробуй для своего способа выше юзать ММХ, я переделал свои под SSE, оказалось хуже :( видмо придется смотреть как грузануть и можно ли в 128 бит 4 пикселя разом...


Sapersky   (24.08.09 20:22[230]

Самый быстрый способ в памяти я показал выше, вообще без всего этого поползновения со ScanLine и шагания по строкам.

Переделал пример Антона с вращением под "правильные" сканлайны:
http://narod.ru/disk/12367000000/TBT_li_right_scanline.rar.html
Исключительно для демонстрации "кто виноват", мерянье органами устраивать не собираюсь. Тем более что всё уже написано до нас, FastLib -> FastFX.Transform32, и гораздо лучше, без плавающей точки и Round, да ещё и со сглаживанием есть вариант.

попробуй для своего способа выше юзать ММХ, я переделал свои под SSE, оказалось хуже :( видмо придется смотреть как грузануть и можно ли в 128 бит 4 пикселя разом...

Может, с выравниванием проблемы? SSE нужно на 16, а не на 8.
Ещё здесь:
http://www.tommesani.com/SSE2MMX.html
в самом конце пишут, что на P3-4 128-битный SSE обрабатывает данные "половинками" по 64 бита, и выигрыш можно получить только за счёт большей развёртки циклов. Может быть, на CoreDuo это исправили, но не факт.


CSS   (26.08.09 07:27[231]

Интересно...)

Чтобы сравнивать насколько "Быстрый канвас" быстр надо мерять скорость выполнения кода...
Мой способ на одном из форумов просто обсмеяли... :(

Пока буду пробовать способ из примера Sapersky (пост 230), но хотелось бы услышать чьё-нибудь мнение...
Ну, например, включать ли создание TBitmap в измерение? Насколько точны измерения и сильно ли зависят от "железа"...

Beermonza, antonn, а как вы измеряете скорость "построения" кадра?


antonn ©   (26.08.09 11:57[232]


> а как вы измеряете скорость "построения" кадра?

тот же самый, что из [230] :)

на каком форуме обсмеяли? :)


Beermonza ©   (26.08.09 21:53[233]

> CSS   (26.08.09 07:27) [231]
> Beermonza, antonn, а как вы измеряете скорость "построения" кадра?

Я вот так:
t := GetTickCount;

{фрагмент кода}

t := GetTickCount - t;
Label1.Caption := 'Время выполнения: '+IntToStr(t)+' мс';


Разумеется, чтобы поточнее знать, нужно повторять код в цикле множество раз и потом оценивать, разделив t на количество повторений измеряемого кода.


antonn ©   (26.08.09 22:26[234]

и юзать QueryPerformanceCounter для более точных измерений


miek   (12.10.09 22:37[235]

неверно. так мерять нельзя ни в коем случае.
скорость выполнения меряется как _минимум_ из длительной (100+) серии повторов, выполненной на приоритете time_critical или realtime. qpf/qpc  - да, так точнее.


antonn ©   (13.10.09 01:19[236]


> неверно. так мерять нельзя ни в коем случае.

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

PS Вы автор spriteutils? приятно видеть, подсмотрел оттуда много чего :)


miek   (13.10.09 08:50[237]

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

да, это я.


MonoLife ©   (13.10.09 10:41[238]


> antonn ©   (13.10.09 01:19) [236]
>
>PS Вы автор spriteutils? приятно видеть, подсмотрел оттуда много чего :)

A вы автор новогодней "кликомании"?


CSS   (13.10.09 14:12[239]

Э... Как-как мерять нельзя?

На максимальных приоритетах ведь получится максимальная скорость... Но это ж вроде всё равно результат на конкретной машине...

А насчёт ''серии повторов'' - я пробовал в цикле делать, но цикл и без ''внутренностей'' много времени съедает... =(


@!!ex ©   (13.10.09 15:19[240]

Делаешь пустой цикл на миллион итераций. Замеряешь время работы.
После чего делаешь не пустой цикл на миллион итераций. Замеряешь время работы. Отнимаешь первый замер. Получаешь время работы алгоритма.


antonn ©   (13.10.09 22:17[241]


> A вы автор новогодней "кликомании"?

угу, и в ней его код =)


MonoLife ©   (14.10.09 03:20[242]


> antonn ©   (13.10.09 22:17) [241]

Очень симпатичная игрушка. Единственный минус, при увеличении поля более, чем 10х15 (по умолчанию) тормоза (на конфиге Sempron 1.6, 768mb ОЗУ, в.а. Radeon 9600).


antonn ©   (15.10.09 00:31[243]

вроде бы тормозит из-за вывода битмапа в UpdatelayredWindow(), точно сейчас не помню. Еще отключение "иконок" должно придать ускорения (даже не знаю, зачем я их туда запихал...)


CSS   (16.10.09 10:33[244]

Это-то я догадался, но у меня слишком мелкий код и оба замера одинаковы...

Так как там нельзя замерять-то (в посте 235)?

И я ещё вот что подумал... А рисовать линии на битмапе как будет быстрее?
Будет ли быстрее через "ScanLine" чем через стандартный "Image1.Canvas.LineTo()" ?


antonn ©   (17.10.09 00:53[245]


> Будет ли быстрее через "ScanLine" чем через стандартный
> "Image1.Canvas.LineTo()" ?

раз в 10 наверное...


Sapersky   (17.10.09 16:08[246]

Я как-то сравнивал фастлибовские функции рисования линий с GDI-шными - примерно одинаково получилось. Откуда "раз в 10" - оно же не через Canvas.Pixels работает.
Может быть, рисование специфических линий (толстых, пунктиром) в GDI помедленнее. Тоже как-то сравнивал - результаты плохо помню, вроде бы вручную быстрее, хотя и не в 10 раз.


CSS   (17.10.09 20:43[247]

Посоветовали попробовать с "Обобщённым алгоритмом Брезенхэма", но чтот не найду именно обобщённого...

Вы через него рисовали?


antonn ©   (17.10.09 22:25[248]

тьфу, прочел рисование по линиям, типа подряд пипкселы перебирать :)


Sapersky   (18.10.09 16:58[249]

Посоветовали попробовать с "Обобщённым алгоритмом Брезенхэма", но чтот не найду именно обобщённого...
Вы через него рисовали?


Сам я реализаций Брезенхема в обозримом прошлом не писал, использовал фастлиб, какая там реализация - особо не вникал. С толстыми линиями - кажется, там только горизонтальные/вертикальные линии были (и поэтому сравнение с GDI не вполне честное :)).
Можно посмотреть исходники других библиотек - в Graphics32 наверняка есть рисование линий, в Antigrain (AggPas).
Но это имеет смысл только если нужны какие-то особые спецэффекты вроде полупрозрачности/антиалиасинга, а так GDI вполне справляется.


DVM ©   (20.10.09 20:54[250]


> Но это имеет смысл только если нужны какие-то особые спецэффекты
> вроде полупрозрачности/антиалиасинга, а так GDI вполне справляется.
>

Кстати, по поводу антиалиазинга. Программы типа Adobe Illustrator особо не заморачиваются с антиалиазингом отдельных линий, а сглаживают всю сцену уже после рисования всего.


dsoft ©   (04.01.10 23:38[251]


> Sapersky
> В FastLIB есть пример рисования плазмы:


Вопрос на засыпку. ScreenSaver Points Ваша программа? Если да, то как с Вами связаться?


dsoft ©   (05.01.10 02:05[252]


> DomiNickDark   (17.03.09 11:53) [101]
> Проблема проста - предпросмотр СкринСейвера не работает.



В XP стандартные примеры предпросмотра не работают. Я использовал такой вариант:

 ParentWnd := StrToInt(ParamStr(2));
 while not IsWindowVisible(ParentWnd) do
   ProcessMessages;

 GetWindowRect(ParentWnd, PreViewRect);

то есть ждём пока XP не отдаст нам нужный контекст и только тогда отрисовываем. Проблемы исчезли.


antonn ©   (05.01.10 02:44[253]

в drkb есть пример который работает


Sapersky   (06.01.10 03:42[254]

ScreenSaver Points Ваша программа? Если да, то как с Вами связаться?

Морфинг геом. фигур с аппаратным рендером - да.
sapersky[собака]mail.ru
Хотя вопросы по реализации лучше задавать на форуме.


гарри   (01.11.15 21:17[255]

Удалено модератором
Примечание: Задай свой вопрос в отдельной ветке


версия для печати
Обсуждение закрыто


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо