IPB
ЛогинПароль:

> ВНИМАНИЕ!

Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.

 
 Ответить  Открыть новую тему 
> Быстрая анимация посредством Delphi
Gothic_Snake
сообщение 22.12.2005 22:04
Сообщение #1


Новичок
*

Группа: Пользователи
Сообщений: 45
Пол: Мужской
Реальное имя: Алексей

Репутация: -  0  +


Существует поверье, что написание анимации посредством 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


Прикрепленные файлы
Прикрепленный файл  EXEcutable.rar ( 149.42 килобайт ) Кол-во скачиваний: 357
Прикрепленный файл  Source.rar ( 2.25 килобайт ) Кол-во скачиваний: 329
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Gothic_Snake
сообщение 23.12.2005 21:48
Сообщение #2


Новичок
*

Группа: Пользователи
Сообщений: 45
Пол: Мужской
Реальное имя: Алексей

Репутация: -  0  +


По просьбе знакомого пишу этот пост.

В дельфи в классе 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;


Ну вот вроде бы и все, что хотел бы сказать, а дальше-у кого-какая фантазия!
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
NorthAngel
сообщение 25.12.2005 9:01
Сообщение #3


Новичок
*

Группа: Пользователи
Сообщений: 25
Пол: Женский

Репутация: -  0  +


Цитата(Gothic_Snake @ 23.12.2005 2:04) *

Существует поверье, что написание анимации посредством Canvas в Delphi очень неблагодарное дело, мол тормоза, мерцание... Кул программеры сразу начинают изучать OpenGL/DX
На это есесно уходит многа времени...
Хочу привести пару примеров работы в Delphi с TCanvas+GDI
Ниже приведен пример заставки с часиками

Пример, конечно, хороший... но нет ли у кого-нибудь статей и т.п. по анимации посредством Canvas в Delphi...
Надоели уже тормоза из-за анимации... mad.gif Не знаю что делать...

Сообщение отредактировано: NorthAngel - 25.12.2005 9:01


--------------------
ошибки легче всего делаются и труднее всего находятся в самых простых местах программы =))
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
GoodWind
сообщение 25.12.2005 13:31
Сообщение #4


Автооответчик
*****

Группа: Модераторы
Сообщений: 1 188
Пол: Мужской
Реальное имя: Александр

Репутация: -  16  +


NorthAngel, вот я и раскручиваю Gothic_Snake`a на серию статей =)


--------------------
Неадекватная чушь может быть адекватным ответом на неадекватный вопрос. Понятно или разжевать?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Gothic_Snake
сообщение 25.12.2005 14:24
Сообщение #5


Новичок
*

Группа: Пользователи
Сообщений: 45
Пол: Мужской
Реальное имя: Алексей

Репутация: -  0  +


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;

Далее, у кого какая фантазия...
Это чисто теоритический пример. Может и с нек. ошибками, главное- идея...
Главное при построении кадра-это оптимизиронанный и быстрый код...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
hardcase
сообщение 8.01.2006 0:02
Сообщение #6


code warrior
****

Группа: Пользователи
Сообщений: 484
Пол: Мужской
Реальное имя: Славен

Репутация: -  8  +


Такая же смена страниц происходит в VCL при прорисовке компонента, если у него стоит DoubleBuffered в True.


Canvas - вещь хорошая, но как-никак медленная. (иногда глючная - о потере контекста молчу)
Вот мелкософт сделал уже давно GDI+. На мой взгляд хорошая вешь, гораздо удобнее написания графики на обычном GDI с использованием известных апишек. Кроме того GDI+ - объектно ориетрированная библиотека и использует в конечном счёте DX.

Сообщение отредактировано: hardcase - 8.01.2006 0:03


--------------------
ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Gothic_Snake
сообщение 8.01.2006 21:12
Сообщение #7


Новичок
*

Группа: Пользователи
Сообщений: 45
Пол: Мужской
Реальное имя: Алексей

Репутация: -  0  +


Цитата(hardcase @ 8.01.2006 3:02) *

Такая же смена страниц происходит в VCL при прорисовке компонента, если у него стоит DoubleBuffered в True.
Canvas - вещь хорошая, но как-никак медленная. (иногда глючная - о потере контекста молчу)
Вот мелкософт сделал уже давно GDI+. На мой взгляд хорошая вешь, гораздо удобнее написания графики на обычном GDI с использованием известных апишек. Кроме того GDI+ - объектно ориетрированная библиотека и использует в конечном счёте DX.

GDI+ никогда DX не использует. Разве что часть DD да и то я совневаюсь в этом...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
hardcase
сообщение 8.01.2006 21:33
Сообщение #8


code warrior
****

Группа: Пользователи
Сообщений: 484
Пол: Мужской
Реальное имя: Славен

Репутация: -  8  +


Пардон, DD. Извините - очепятался.
DD использует - c хедерами даже модуль поставляется DirectDraw.
Там кое-какие интефейсы прописываются...


--------------------
ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Gothic_Snake
сообщение 10.01.2006 16:11
Сообщение #9


Новичок
*

Группа: Пользователи
Сообщений: 45
Пол: Мужской
Реальное имя: Алексей

Репутация: -  0  +


Цитата(hardcase @ 9.01.2006 0:33) *

Пардон, DD. Извините - очепятался.
DD использует - c хедерами даже модуль поставляется DirectDraw.
Там кое-какие интефейсы прописываются...

Бывает... А есть у тя эти хедеры? Скинь если не трудно..
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
hardcase
сообщение 11.01.2006 16:15
Сообщение #10


code warrior
****

Группа: Пользователи
Сообщений: 484
Пол: Мужской
Реальное имя: Славен

Репутация: -  8  +


Цитата(Gothic_Snake @ 10.01.2006 16:11) *

Бывает... А есть у тя эти хедеры? Скинь если не трудно..

Вот джедайские хедеры с сэмплами.

Кончно, реализация классов не очень удобна.
Я в своих пограммах писал собстверрые классы-адаптеры для уже объявленных. Просто модель классов, начисто скопирована из gdiplus.h, написанного на C++

Но в целом библиотека гораздо удобнее чем обычные API.

Сообщение отредактировано: hardcase - 11.01.2006 16:16


Прикрепленные файлы
Прикрепленный файл  gdiplus.rar ( 685.08 килобайт ) Кол-во скачиваний: 247


--------------------
ИзВ ин ИтЕ зА нЕ рОв НЫй П оч ЕРк
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Gothic_Snake
сообщение 11.01.2006 20:02
Сообщение #11


Новичок
*

Группа: Пользователи
Сообщений: 45
Пол: Мужской
Реальное имя: Алексей

Репутация: -  0  +


Большое спасибо... Постараюсь порыться в них =)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

- Текстовая версия 17.07.2025 22:49
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"