![]() |
Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.
![]() ![]() |
![]() |
Gothic_Snake |
![]()
Сообщение
#1
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 45 Пол: Мужской Реальное имя: Алексей Репутация: ![]() ![]() ![]() |
Существует поверье, что написание анимации посредством Canvas в Delphi очень неблагодарное дело, мол тормоза, мерцание... Кул программеры сразу начинают изучать OpenGL/DX
На это есесно уходит многа времени... Хочу привести пару примеров работы в Delphi с TCanvas+GDI Ниже приведен пример заставки с часиками Код unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Buttons,commctrl; var Window:HWND; DC:Hdc; DCCanv:TCanvas; const SnowCount=2000; type TSnow=class dc:Integer; col:Tcolor; cnv:Tcanvas; X,Y:Integer; Dx:Integer; dy:Integer; widht,Height:Integer; Constructor Create; Procedure Draw; end; TForm1 = class(TForm) PaintBox1: TPaintBox; Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure FormResize(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure FormKeyPress(Sender: TObject; var Key: Char); procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); private { Private declarations } public { Public declarations } f:Boolean; Snows:array of TSnow; col:Tcolor; dc:Integer; buf:TBitmap; x:Integer; dx:integer; Function Rct:Trect; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var i:integer; fx:byte; begin x:=5; dx:=5; dc:=1; ShowCursor(false); buf:=TBitmap.Create; SetLength(snows,snowcount); for i:=0 to snowcount -1 do begin Snows[i]:=TSnow.Create; with Snows[i] do begin Dx:=random(3)-random(3); dy:=random(3)+1; widht:=Screen.Width; Height:=Screen.Height; X:=random(Screen.Width); Y:=random(Screen.Height); cnv:=buf.Canvas; fx:=random(256); col:=rgb(fx,fx,fx); end; end; Left:=0; Top:=0; Width:=Screen.Width; Height:=Screen.Height; end; procedure TForm1.FormResize(Sender: TObject); begin buf.Width:=PaintBox1.Width; buf.Height:=PaintBox1.Height; end; function TForm1.Rct: Trect; begin Result:=PaintBox1.ClientRect; end; procedure TForm1.Timer1Timer(Sender: TObject); var i:integer; begin col:=rgb(GetrValue(col)+dc,GetgValue(col)+dc,GetBValue(col)+dc); if (col=$00FFFFff)or(col=0) then dc:=-dc; with buf.Canvas do begin Brush.Color:=clBlack; FillRect(Rct); Font.Color:=COL; Font.Name:='Courier New'; font.Size:=70; x:=x+dx; if (x>460)or(x=5) then dx:=-dx; TextOut(x,600,'© By Snake'); font.Size:=50; TextOut(x+120,700,timetostr(now)); end; for i:=0 to SnowCount-1 do Snows[i].Draw; PaintBox1.Canvas.CopyRect(rct,buf.Canvas,rct); end; constructor TSnow.Create; begin dc:=1; end; procedure TSnow.Draw; var fx:byte; begin col:=rgb(GetrValue(col)+dc,GetgValue(col)+dc,GetBValue(col)+dc); if (col=$00ffffff)or(col=0) then dc:=-dc; x:=x+dx+random(3)-random(3); y:=y+dy; if (x>=widht)or(x<0)or(y>=Height) then begin dx:=random(3)-random(3); dy:=random(3)+1; y:=0; x:=random(screen.Width); fx:=random(256); col:=rgb(fx,fx,fx); end; cnv.Pixels[x,y]:=col; end; procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if not f then begin f:=true; exit; end; end; procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin close; end; procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin close; end; end. frm object Form1: TForm1 Left = 215 Top = 132 BorderStyle = bsNone Caption = 'Form1' ClientHeight = 447 ClientWidth = 644 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] KeyPreview = True OldCreateOrder = False Position = poDefault Visible = True OnCreate = FormCreate OnKeyPress = FormKeyPress OnResize = FormResize PixelsPerInch = 96 TextHeight = 13 object PaintBox1: TPaintBox Left = 0 Top = 0 Width = 644 Height = 447 Align = alClient OnMouseDown = PaintBox1MouseDown end object Timer1: TTimer Interval = 1 OnTimer = Timer1Timer Left = 8 Top = 8 end end Сообщение отредактировано: GoodWind - 22.12.2005 22:11 Прикрепленные файлы ![]() ![]() |
Gothic_Snake |
![]()
Сообщение
#2
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 45 Пол: Мужской Реальное имя: Алексей Репутация: ![]() ![]() ![]() |
По просьбе знакомого пишу этот пост.
В дельфи в классе TCanvas существует метод TCanvas.pixels[x,y], с помошью которого можно получить цвет пикселя на холсте. Этот метод очень медленно работает из-за перерисовки всего холста после каждой операции считывания/записи. Существует и другой способ доступа к пикселю на холсте. Этот доступ намного быстрее, так как работает напрямую с блоком бамяти, где распологается карта битов изображения. Далее привожу метод реализации этого способа: type
TRGB24=record //описание записи для чтения. Внимание расположение цветов не как в TColor!
b,//1
g,//2
r:byte;//3
end;
ARGB24=array [0..0] of TRGB24;
PRGB24=^ARGB24;
//аналогично:
TRGB32=record
b,//1
g,//2
r,//3
a:byte;//4 - Alpha канал
end;
ARGB32=array [0..0] of TRGB32;
PRGB32=^ARGB32;
TRGB16=record //режим 5-5-5 или 5-6-5
bg,//1
gr:Byte//2
end;
ARGB16=array [0..0] of TRGB16;
PRGB16=^ARGB16;
//далее пример процедуры FadeDown для 24 битового изображения
procedure TForm1.FadeDown;
var
BitMap : TBitMap;
x,y : Integer;
p : PRGB;
step:byte;
begin
bitmap:=tbitmap.create;
BitMap.LoadFromFile('test.bmp');
try
BitMap.PixelFormat:=pf24bit;
// Указываем битмапу, что изображения в нашем случае 24 бита!
// иначе может привести к ошибке, в случае, если изображение не является 24-битным
for step:=0 to 255 do
begin
for y := 0 to BitMap.Height -1 do
begin
P := BitMap.ScanLine[y];//считываем линию в указатель на массив P
for x := 0 to BitMap.Width-1 do
begin
if p[x].r>0 then dec(p[x].r) else p[x].r:=0;//Обращение поэлементно к каждому цвету
if p[x].g>0 then dec(p[x].g) else p[x].g:=0;//Обращение поэлементно к каждому цвету
if p[x].b>0 then dec(p[x].b) else p[x].b:=0;//Обращение поэлементно к каждому цвету
end;
end;
BitBlt(Canvas.Handle,0,0,Width,Height,BitMap.Canvas.Handle,0,0,SRCCOPY);
//Обновление изображения Обязательно! иначе результат виден не будет!
end;
finally
bitmap.free;
end;
end;
Ну вот вроде бы и все, что хотел бы сказать, а дальше-у кого-какая фантазия! |
NorthAngel |
![]()
Сообщение
#3
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 25 Пол: Женский Репутация: ![]() ![]() ![]() |
Существует поверье, что написание анимации посредством Canvas в Delphi очень неблагодарное дело, мол тормоза, мерцание... Кул программеры сразу начинают изучать OpenGL/DX На это есесно уходит многа времени... Хочу привести пару примеров работы в Delphi с TCanvas+GDI Ниже приведен пример заставки с часиками Пример, конечно, хороший... но нет ли у кого-нибудь статей и т.п. по анимации посредством Canvas в Delphi... Надоели уже тормоза из-за анимации... ![]() Сообщение отредактировано: NorthAngel - 25.12.2005 9:01 -------------------- ошибки легче всего делаются и труднее всего находятся в самых простых местах программы =))
|
GoodWind |
![]()
Сообщение
#4
|
![]() Автооответчик ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 1 188 Пол: Мужской Реальное имя: Александр Репутация: ![]() ![]() ![]() |
NorthAngel, вот я и раскручиваю Gothic_Snake`a на серию статей =)
-------------------- Неадекватная чушь может быть адекватным ответом на неадекватный вопрос. Понятно или разжевать?
|
Gothic_Snake |
![]()
Сообщение
#5
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 45 Пол: Мужской Реальное имя: Алексей Репутация: ![]() ![]() ![]() |
2NorthAngel
Хорошо. Быстрая анимация без тормозов? По средством Канваса в Дельфи можно написать анимацию только в разумных пределах. Это из-за того, что битлидинг (копирование одной области видеопямяти в другую) происходит с исполизование процессора (CPU). В отличии от DirectX/OpenGL, где на прорисовку кадра можно направить графический процессов вашей видеокары (GPU), который работает только со своей пямятью (видеопямятью), что соответственно работает намного быстрее. Вы спросите: Почему в досе это делается быстрее? Отвечаю: В досе у вас есть доступ напрямую к видеопамяти (адрес страницы). В Windows же это происходит через API интервейс, и напрямую к видеопамяти обратиться вам никто не даст. Раз затронулась такакя тема, то как же происходит рисование в Windows? - Посредством API функций GDI и GDI+ (GDI+ это нововведение со времен WinXP/Win2003). Класс TCanvas в Delphi - это обыкновенная "обертка" этих функций. Как происходит быстое рисование: Идея такова, и еще лучше пока еще не придумали: Сначало все рисуется в памяти, далее содержимое памяти копирутся в видео пямять (идея 2 буфферизации). Как это делается в дельфи: Код ... uses graphics //! переопределяется класс TBitmap ... var bmBackBuff:TBitmap//Задний буфер. В роли видеопямяти у нас будет канвас нашей формы. ... Procedure TForm1.formCreate(sender:TObject); begin ... bmBackBuff:=TBitmap.Create;//Создаем задний буфер и выделяем под него пямять в озу bmBackBuff.width:=self.width; //задаем размер bmBackBuff.height:=self.height;//нашему заднему буферу, иначе мы будем рисовать в пространстве 0х0 пикселей :) ... end; Procedure Flip;//Смена страниц :) begin BitBlt(form1.canvas.handle,//Куда копируем изображение 0,0,//С какого пикселя начать bmBackBuff.width,bmBackBuff.width,//размер копируемого изображения bmBackBuff.canvas.handle,//откуда копируем SRCCOPY);//тип копирования (SRCCOPY/SRCPAINT/SRCINVERT/SRCCLEAR/SRCAND) end; Procedure Draw;//здесь мы будем рисовать begin //Производим рисование на задний буффер with bmBackBuff.canvas do begin brush.color:=clblack; fillrect(0,0,bmbackbuff.width,bmbackbuff.height); font.size:=72; font.name:='Courier New'; textout(10,10,timetostr(NOW)); //и т.д. end; end; Procedure Render;//Как звучит! :) begin Draw; Flip; end; procedure tform1.formshow(sender:TObject); begin render; end; Далее, у кого какая фантазия... Это чисто теоритический пример. Может и с нек. ошибками, главное- идея... Главное при построении кадра-это оптимизиронанный и быстрый код... |
hardcase |
![]()
Сообщение
#6
|
![]() code warrior ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 484 Пол: Мужской Реальное имя: Славен Репутация: ![]() ![]() ![]() |
Такая же смена страниц происходит в VCL при прорисовке компонента, если у него стоит DoubleBuffered в True.
Canvas - вещь хорошая, но как-никак медленная. (иногда глючная - о потере контекста молчу) Вот мелкософт сделал уже давно GDI+. На мой взгляд хорошая вешь, гораздо удобнее написания графики на обычном GDI с использованием известных апишек. Кроме того GDI+ - объектно ориетрированная библиотека и использует в конечном счёте DX. Сообщение отредактировано: hardcase - 8.01.2006 0:03 -------------------- ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
|
Gothic_Snake |
![]()
Сообщение
#7
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 45 Пол: Мужской Реальное имя: Алексей Репутация: ![]() ![]() ![]() |
Такая же смена страниц происходит в VCL при прорисовке компонента, если у него стоит DoubleBuffered в True. Canvas - вещь хорошая, но как-никак медленная. (иногда глючная - о потере контекста молчу) Вот мелкософт сделал уже давно GDI+. На мой взгляд хорошая вешь, гораздо удобнее написания графики на обычном GDI с использованием известных апишек. Кроме того GDI+ - объектно ориетрированная библиотека и использует в конечном счёте DX. GDI+ никогда DX не использует. Разве что часть DD да и то я совневаюсь в этом... |
hardcase |
![]()
Сообщение
#8
|
![]() code warrior ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 484 Пол: Мужской Реальное имя: Славен Репутация: ![]() ![]() ![]() |
Пардон, DD. Извините - очепятался.
DD использует - c хедерами даже модуль поставляется DirectDraw. Там кое-какие интефейсы прописываются... -------------------- ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
|
Gothic_Snake |
![]()
Сообщение
#9
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 45 Пол: Мужской Реальное имя: Алексей Репутация: ![]() ![]() ![]() |
|
hardcase |
![]() ![]()
Сообщение
#10
|
![]() code warrior ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 484 Пол: Мужской Реальное имя: Славен Репутация: ![]() ![]() ![]() |
Бывает... А есть у тя эти хедеры? Скинь если не трудно.. Вот джедайские хедеры с сэмплами. Кончно, реализация классов не очень удобна. Я в своих пограммах писал собстверрые классы-адаптеры для уже объявленных. Просто модель классов, начисто скопирована из gdiplus.h, написанного на C++ Но в целом библиотека гораздо удобнее чем обычные API. Сообщение отредактировано: hardcase - 11.01.2006 16:16 Прикрепленные файлы ![]() -------------------- ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
|
Gothic_Snake |
![]()
Сообщение
#11
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 45 Пол: Мужской Реальное имя: Алексей Репутация: ![]() ![]() ![]() |
Большое спасибо... Постараюсь порыться в них =)
|
![]() ![]() |
![]() |
Текстовая версия | 17.07.2025 22:49 |