Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.06.2008, 11:43   #1
Format C:
Пользователь
 
Регистрация: 11.03.2007
Сообщений: 92
По умолчанию Движение песка

Приветствую всех.

Написал програмку которая моделирует падение песка (грубо конечно, но по другому пока не получается), всё вроде хорошо, но довольно сильно тормозит. Кто может подсказать, где оптимизировать код?

В архиве исходники и несколько карт.
Вложения
Тип файла: rar Sand.rar (18.8 Кб, 58 просмотров)

Последний раз редактировалось Format C:; 07.06.2008 в 11:52.
Format C: вне форума Ответить с цитированием
Старый 07.06.2008, 12:49   #2
alexBlack
Участник клуба
 
Регистрация: 12.10.2007
Сообщений: 1,204
По умолчанию

вот это место:

Код:
    For J:=0 To SandPoleHeight-1 Do
      For I:=0 To SandPoleWidth-1 Do
      Case SandPole[I, J] Of
        SandPoleBusy:
        Begin
          Brush.Color:=clRed;
          FillRect(Rect(I, J, I+1, J+1));
        End;
...
Это практически попиксельный вывод. Быстрее будет с использованием TBitMap.ScanLine

У Вас там в Paint вызывается всего две процедуры. Лучше бы сначала посмотреть что медленнее - paintSand или moveSand и уже ее оптимизировать.
alexBlack вне форума Ответить с цитированием
Старый 08.06.2008, 12:54   #3
Zeraim
Ra-Ra ?
Форумчанин
 
Аватар для Zeraim
 
Регистрация: 06.03.2008
Сообщений: 286
По умолчанию

Прикольно, тока странно что песок по стенкам ползает, оже вроде когда скатывается с поверхностей немного вперед пролетает =\\
Zeraim вне форума Ответить с цитированием
Старый 08.06.2008, 13:56   #4
Net
;-)
Пользователь
 
Регистрация: 18.07.2007
Сообщений: 69
По умолчанию

Цитата:
Сообщение от Format C: Посмотреть сообщение
Приветствую всех.

Написал програмку которая моделирует падение песка (грубо конечно, но по другому пока не получается), всё вроде хорошо, но довольно сильно тормозит. Кто может подсказать, где оптимизировать код?

В архиве исходники и несколько карт.
Используйте профайлеры, удобнее вещи нету.
Скрин профиля (куча 20х20, плотность 20):
http://img59.imageshack.us/img59/777...profileky0.png
Net вне форума Ответить с цитированием
Старый 26.06.2008, 07:48   #5
Format C:
Пользователь
 
Регистрация: 11.03.2007
Сообщений: 92
По умолчанию

Привет всем.

2alexBlack:
Я немножко не понял со ScanLine.
Что не правильно в этой строчке. В ней я пытаюсь запихнуть данные с указателя в динамический массив, но программа слетает с ошибкой записи по адрессу.

Код:
Type
  PRGBPixel = ^TRGBPixel;
  TRGBPixel = Packed Record
    B, G, R: Byte;
  End;

  PRGBArray = ^TRGBArray;
  TRGBArray = Array Of TRGBPixel;

RGBArray^:=TRGBArray(Bitmap.ScanLine[Index]^);
Если массив не динамический, всё работает.

Тестовая программа в архиве.

2Net:
Да, очень удобная штука.
При отладке и оптимизации вещь незаменимая.
Вложения
Тип файла: rar TestScanLine.rar (2.8 Кб, 20 просмотров)
Format C: вне форума Ответить с цитированием
Старый 26.06.2008, 08:31   #6
alexBlack
Участник клуба
 
Регистрация: 12.10.2007
Сообщений: 1,204
По умолчанию

А зачем еще раз копировать в буфер ?
возвращайте саму ссылку

PRGBArray(Bitmap.ScanLine[Index]);

Не вижу Вашего Вызова GetLine, но

If Index>Bitmap.Height Then Exit; // index in 0..Bitmap.Height-1
//SetLength(RGBArray^, Bitmap.Height); // Bitmap.Width

и с PRGBPixel - три байта это для 24-битного формата. Может быть и по-другому. Поэтому все-таки лучше использовать ссылку, которую возвращает ScanLine. То есть не использовать дополнительную функцию GetLine, а делать процедуру для каждого метода обработки и передавать в нее BitMap. Например

Код:
procedure <МетодОбработки>(B:TBitMap, <дополнительные параметры>)
begin
    // Здесь получаем строки по очереди 
    // по формату BitMap решаем как расположены байты в строке 
    // и обрабатываем их по какому-то алгоритму.
end;
Посмотрите в верхней теме в разделе про игры много примеров про ScanLine
alexBlack вне форума Ответить с цитированием
Старый 26.06.2008, 10:38   #7
Format C:
Пользователь
 
Регистрация: 11.03.2007
Сообщений: 92
По умолчанию

2alexBlack:

Цитата:
А зачем еще раз копировать в буфер ?
Хотелось сделать уневерсальный модуль для работы с пикселями в памяти, т.к. довольно часто есть такая необходимисть.

Но почему не коррктно происходит присваивание с указателя, если массив динамический?
Format C: вне форума Ответить с цитированием
Старый 26.06.2008, 11:23   #8
alexBlack
Участник клуба
 
Регистрация: 12.10.2007
Сообщений: 1,204
По умолчанию

Цитата:
Сообщение от Format C: Посмотреть сообщение
Но почему не коррктно происходит присваивание с указателя, если массив динамический?
По-моему проще так:

Код:
Type
  PRGBPixel = ^TRGBPixel;
  TRGBPixel = Packed Record
    R, G, B: Byte;
  End;

  PRGBArray = ^TRGBArray;
  TRGBArray = Array [word] Of TRGBPixel;

var Buf:TBitMap;
    i:integer;
begin
   Buf:=TBitmap.Create;
   Buf.LoadFromFile('Test.bmp');
   Buf.PixelFormat:=pf24bit;

   for I:=0 To Buf.width-1 Do begin
     Scan := buf.ScanLine[0];
     lbLog.Items.Add('Index: '+IntToStr(I)+
                     ' R: '+ IntToStr(PRGBArray(Scan)[I].R)+
                     ' G: '+ IntToStr(PRGBArray(Scan)[I].G)+
                     ' B: '+ IntToStr(PRGBArray(Scan)[I].B)+' ');
   end;
Большая часть кода из Вашего примера.
-------------------------------------------
Что касается динамических массивов.
Вы передаете адрес переменной, хранящей ссылку на динамический массив.
По идее нужно писать:

RGBArray^^:=TRGBArray(Bitmap.ScanLi ne[Index]^);

но компилятор не поддерживает разименование динамических массивов.
Можно, конечно, это обойти. Например:

Код:
type
  TDRGBArray = Array Of TRGBPixel;

Function GetLine1(Const Bitmap: TBitmap; Const RGBArray: TDRGBArray; Const Index: integer): Boolean;
Begin
  Result:=False;
  If Index >= Bitmap.Height Then Exit;
  //RGBArray := TDRGBArray(Bitmap.ScanLine[Index]^)
  move(Bitmap.ScanLine[Index]^, pointer(RGBArray)^, BitMap.Width*sizeOF(TRGBPixel));
  Result:=True;
End;

var V:TDRGBArray;
    i:integer;
begin
   SetLength(V, Buf.Width);
   GetLine1(Buf, V, 0);;
   finalize(V);
Но это использование знаний о внутренней структуре объктов Object Pascal.
А значит, решение скорее всего не переносимо.
И еще, создание динамического массива и копирование в него - это затраты по времени.
Не проще ли использовать просто ссылку, как приведено в примере выше.

Последний раз редактировалось alexBlack; 26.06.2008 в 13:00.
alexBlack вне форума Ответить с цитированием
Старый 26.06.2008, 13:51   #9
Format C:
Пользователь
 
Регистрация: 11.03.2007
Сообщений: 92
По умолчанию

2alexBlack:
Вроде как получилось, но есть один момент:
Так как массив TRGBArray не динамический, он занимает почти 200Кб памяти, притом бОльшая часть его не используется. Можно ли как-нибудь уменшить размер, сохранив универсальность модуля?

Что у меня получилось, можно посмотреть в архиве.
Есть ещё недочёты?

Цитата:
Но это использование знаний о внутренней структуре объктов Object Pascal.
А можно где-нибудь по подробней почитать об этом?
Вложения
Тип файла: rar TestScanLine.rar (2.9 Кб, 21 просмотров)
Format C: вне форума Ответить с цитированием
Старый 26.06.2008, 15:51   #10
alexBlack
Участник клуба
 
Регистрация: 12.10.2007
Сообщений: 1,204
По умолчанию

Цитата:
Сообщение от Format C: Посмотреть сообщение
2alexBlack:
Вроде как получилось, но есть один момент:
Так как массив TRGBArray не динамический, он занимает почти 200Кб памяти, притом бОльшая часть его не используется. Можно ли как-нибудь уменшить размер, сохранив универсальность модуля?
Это Вы про это говорите:
TRGBArray = Array[Word] Of TRGBPixel;

Это просто объявление типа. Места оно не занимает. Память распределяется при вызове ScanLine (столько, сколько нужно) и мы получаем ссылку на нее. Аэто:
PRGBArray(Scan)^[I].R
просто приведение типа.

Если же Вы хотите создавать такие массивы, то вот так:
Var RGBArray: TRGBArray;
не нужно.

Распределяйте память сами:
Код:
Var RGBArray: PRGBArray;
begin
    getmem(RGBArray, sizeOf(PRGBPixel) * 100);   
    ...
    freemem(RGBArray);
но, повторяю, этого не нужно. Зачем вводить дополнительные массивы.
Используйте ScanLine.

Код:
  For I:=0 To Buf.Width-1 Do begin
      PRGBArray(Scan)^[I].R:=255-Round(I*255/Buf.Width);
      PRGBArray(Scan)^[I].G:=0;
      PRGBArray(Scan)^[I].B:=0;
  End;
А выносить в модуль для дальнейшего использования нужно не GetLine/SetLine, а весь этот цикл. Назвать его как-то осмысленно и вызывать при необходимости. Например,

procedure fillGradient(buf:TBitMap);

Цитата:
А можно где-нибудь по подробней почитать об этом?
Описание внутреннего формата переменных всегда было в документации.
например, Developer Studio 2006 Reference/Internal Data Formats
На русском видел в описании от Borland Pascal 7.0.
alexBlack вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Движение картинки &RiU Помощь студентам 2 28.05.2008 23:46
движение по эллипсу Оля Помощь студентам 2 08.05.2007 00:50
Движение Mickle Общие вопросы Delphi 5 19.04.2007 23:24
Движение по окружности Mickle Общие вопросы Delphi 3 13.04.2007 16:24
Движение камеры LepihinMS Gamedev - cоздание игр: Unity, OpenGL, DirectX 2 16.03.2007 20:46