Перейти к содержанию
Fire Monkey от А до Я
  • 0

Скроллинг на канве


Letos

Вопрос

Здравствуйте. Подскажите, пожалуйста, правильно ли я делаю скроллинг фона? Собственно интересует, рационально ли здесь использовать метод DrawBitmap? При этом же прорисовывается вся канва. (И да, помещать картинку на TImage и двигать её я пробовал, так ГОРАЗДО медленнее.) Ведь даже на игровых приставках имелась аппаратная функция скроллинга экрана, реализовано ли это как-то в FMX? Пример я прилагаю, включая exe файл. Как видим, двигается не идеально плавно.

//---------------------------------------------------------------------------

#include <fmx.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;

TBitmap *MapBmImage = new TBitmap;
String InitialDirectory;


float MapVx=150; // скорость по X, пиксели в секунду

float MapOutX=0, MapOutY=0; // координаты левого верхнего угла, с которого выводится фон
float ScreenMapWidth, ScreenMapHeight; // ширина и высота фона на экране
float MapOutXLimit; //крайняя правая точка карты, которая может быть отражена
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
boolean LoadMapFile() //загрузка карты
{
    String filename=InitialDirectory+"\\2dbackground_b.png";
    if(!FileExists(filename)) return false;

    MapBmImage->LoadFromFile(filename);

    return true;

}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    InitialDirectory=ExtractFileDir(ParamStr(0)); // the path and file name of the executing program
    LoadMapFile();
}
//---------------------------------------------------------------------------


void DrawBackground()
{
    TPaintBox *ScreenMap=Form1->PaintBox1; //где отрисовывается карта на экране

    TRectF MapRect = TRectF(MapOutX, MapOutY, MapOutX+ScreenMapWidth, MapOutY+ScreenMapHeight);
    TRectF ScreenRect = TRectF(0, 0, ScreenMapWidth, ScreenMapHeight);

    ScreenMap->Canvas->BeginScene();
    ScreenMap->Canvas->DrawBitmap(MapBmImage,MapRect,ScreenRect,255);
    ScreenMap->Canvas->EndScene();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
    ScreenMapWidth=PaintBox1->Width;
    ScreenMapHeight=PaintBox1->Height;

    MapOutXLimit=MapBmImage->Width-ScreenMapWidth;

}
//---------------------------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    if (MapOutX>=MapOutXLimit) MapVx=-1* abs(MapVx);
    else if (MapOutX<=0) MapVx=abs(MapVx);


    static DWORD LastTick=0; //из-за неравномерного срабатывания таймера
    DWORD Tick;
    float step;
    Tick=GetTickCount();
    if(LastTick!=0)
    {
        step=(float)(Tick-LastTick)/1000; // столько секунд прошло
    }
    else
    {
        step=(float)Timer1->Interval/1000;
    }


    LastTick=Tick;


    float dx; //на столько сдвигаем карту по X
    dx=MapVx*step;

    MapOutX+=dx;
    if (MapOutX>MapOutXLimit) MapOutX=MapOutXLimit;
    if (MapOutX<0) MapOutX=0;

    PaintBox1->Repaint();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::PaintBox1Paint(TObject *Sender, TCanvas *Canvas)
{
    DrawBackground();
}
//---------------------------------------------------------------------------


BackgroundScroll.zip

Изменено пользователем Letos
Ссылка на комментарий
  • Ответы 61
  • Создана
  • Последний ответ

Лучшие авторы в вопросе

Рекомендуемые сообщения

  • 0
5 часов назад, Barbanel сказал:

Может использоваться GDI (это из другой области) либо ЦПУ.

Первым делом FMX пытается использовать аппаратное ускорение (DirectX на Windows), при невозможности - GDI+.

Посмотрите исходники и увидите на каком канвасе все рисуется.

Ссылка на комментарий
  • 0
    static DWORD LastTick=0; //из-за неравномерного срабатывания таймера
    DWORD Tick;
    float step;
    Tick=GetTickCount();
    if(LastTick!=0)
    {
        step=(float)(Tick-LastTick)/1000; // столько секунд прошло
    }
    else
    {
        step=(float)Timer1->Interval/1000;
    }


    LastTick=Tick;

с логикой LastTick ошибок нету?

Изменено пользователем severin696
Ссылка на комментарий
  • 0
23 часа назад, severin696 сказал:

с логикой LastTick ошибок нету?

А в чём? else срабатывает только в первом случае. Далее всегда идёт по выполнению условия. 

Я склоняюсь к мысли, что тут дело именно в таймере, в том, что TTimer работает неравномерно. Как я говорил, где-то видел совет использовать "мультимедийный таймер", но не знаю, что это такое.

Ссылка на комментарий
  • 0

неважно как работает таймер и мультимедийный он или нет )

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

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

Ссылка на комментарий
  • 0

не учёл static...

смотри Multimedia Timer на MSDN. или вот:

uses MMSystem; // подключаем Win32 multimedia API (Winapi.MMSystem)

mmResult: Integer; // ID таймера

procedure TimeCallBack(TimerID, Msg: word; dwUser, dw1, dw2: DWORD); stdcall; // callback функция
begin
    form1.Timer1Timer(nil); // рисуем
end;

mmResult:=TimeSetEvent(20, 0, @TimeCallBack, 0, TIME_PERIODIC); // создаём таймер

TimeKillEvent(mmResult); // удаляем таймер

и идеально, если step не вычислять ( step:=0.02; )

Изменено пользователем severin696
Ссылка на комментарий
  • 0
В 07.03.2019 в 18:35, Letos сказал:

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

Может вам пойти простым путем - написать web-приложение (карта OpenStreetMap, маркеры на карте, немного JS). Все будет в браузере, плавно. При желании сможете засунуть все это в приложение, загрузив в TWebBrowser. Со своим советом я исходил их предположения что вам нужна карта и двигающиеся по ней картинки троллейбусов ?

Ссылка на комментарий
  • 0

Я десять лет занимался такой диспетчерской в Екатеринбурге. 

На js карты не вся функциональность удобно влазит. И производительности не хватает для больших объемов.

Хотя если просто показать кто где едет, конечно норм. Есть на сайте ettu.ru 

Ссылка на комментарий
  • 0
В 04.04.2019 в 07:54, Евгений Корепов сказал:

Со своим советом я исходил их предположения что вам нужна карта и двигающиеся по ней картинки троллейбусов

Верно. Хоть вопрос не в реализации навигатора. (Если интересно, там, у меня, собственно, сервер принимает СМСки с навигаторов и постоянно выкладывает в текстовый лог-файл, а я постоянно считываю. Работает у нас и старая (московская, как называем) программа, и она, полагаю, считывает не из текста, а более напрямую. Но моя программа работает вполне, и там скроллинга (у меня скроллируется при зажатой кнопке мыши), реализованного по описанному выше методу, хватает.) Но почему создал тему - заинтересовало - рационален ли такой метод, пусть не для этого проекта (по навигации), а на будущее. И до создания темы, я, наверное, наивно полагал, что у PC видеокарты имеются какие-то аппаратные функции скроллинга. 

Ссылка на комментарий
  • 0
В 31.03.2019 в 17:34, krapotkin сказал:

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

Ну, то, что выложил тут - пробовал же и без приращений (просто вам не показывал) - результат такой же... 

Ссылка на комментарий
  • 0

функция скроллинга чего ? видеокарта постоянно отрисовывает свой буфер и даже если она сдвинет его на 1 пиксель какой-то магией, то недостающий пиксел с другой стороны кто нарисует??

вы рисуете все на битмап, который чуть больше окна просмотра.

окно сдвигается. битмап не меняется. потом, когда мы подошли к границам битмапа, отрисовываем новое поле карты

а поверх все равно НЕПРЕРЫВНО перерисовываются новые положения транспорта

Ссылка на комментарий
  • 0
1 час назад, krapotkin сказал:

функция скроллинга чего ? видеокарта постоянно отрисовывает свой буфер и даже если она сдвинет его на 1 пиксель какой-то магией, то недостающий пиксел с другой стороны кто нарисует??

Если бы так , то линию в пиксель шириной нарисовал бы процессором - всяко быстрее, чем всю поверхность перерисовывать.

 

Изменено пользователем Letos
Ссылка на комментарий
  • 0

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

а вот кусок картинки (карты) шириной в пиксель (и в 1000 пикселей тоже) видеокарта копирует со скоростью света))

Ссылка на комментарий
  • 0
1 минуту назад, krapotkin сказал:

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

а вот кусок картинки (карты) шириной в пиксель (и в 1000 пикселей тоже) видеокарта копирует со скоростью света))

Так транспорт и надписи - это уже поверх. А линию - в чём проблемы? Да хотя бы, так же, как в моём примере, сделав  TRectF шириной в пиксель.

Ссылка на комментарий
  • 0
5 минут назад, krapotkin сказал:

а вот кусок картинки (карты) шириной в пиксель (и в 1000 пикселей тоже) видеокарта копирует со скоростью света))

Так, значит, рисовать может с такой скоростью, а сдвигать - нет?

 

Ссылка на комментарий
  • 0
2 часа назад, krapotkin сказал:

если она сдвинет его на 1 пиксель какой-то магией

Была такая приставка Famicom (Dendy). Процессор...  если не Z80, то не многим сильнее (или слабее). Был советский компьютер Вектор 06-Ц - проц ещё медленнее. И т.п. Но аппаратный сколлинг там был реализован. Те процессоры бы явно не потянули, если бы делали скроллинг они. Так что за магия?

Изменено пользователем Letos
Ссылка на комментарий
  • 0

и тогда никто ничего не сдвигал. просто говорил, какой символ где на экран вывести

картинки были из аппаратного знакогенератора  80*40*16 цветов

невелика мудрость )))

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

Ссылка на комментарий
  • 0
41 минуту назад, krapotkin сказал:

и тогда никто ничего не сдвигал. просто говорил, какой символ где на экран вывести

не символ. Именно пиксели, фон, причём плавно. Посмотри информацию, если не знаком с этой темой. 

Ссылка на комментарий
  • 0
1 час назад, krapotkin сказал:

картинки были из аппаратного знакогенератора  80*40*16 цветов

Это текстовый режим - то, о чём ты говоришь

Изменено пользователем Letos
Ссылка на комментарий
  • 0
59 минут назад, krapotkin сказал:

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

Если можно сдвинуть железом (или видеокартой) без участия CPU, то это быстрее

Ссылка на комментарий
  • 0
3 часа назад, Letos сказал:

Была такая приставка Famicom (Dendy). Процессор...  если не Z80, то не многим сильнее (или слабее). Был советский компьютер Вектор 06-Ц - проц ещё медленнее. И т.п. Но аппаратный сколлинг там был реализован. Те процессоры бы явно не потянули, если бы делали скроллинг они. Так что за магия?

Тогда все было несколько проще - видеопамять была просто частью оперативной памяти, и видеокарта просто отрисовывала на экране содержимое памяти начиная с заданного адреса. 1 байт = 1 пиксел. Ширина экрана 320 пикселей. Вы говорили видеокарте установить смещение в 1000 байт и она отрисовыла все начиная с тысячного байта. Потом вы устанавливали смещение видеобуфера в 1320 байт (+1 строка) - и вот уже кадр на экране сместился на 1 пиксель выше. Повторяем на каждый тик - и у вас картинка скроллится снизу вверх.

Сейчас у видеокарт все организованно сложнее, но принимая во внимание их безумную производительность, вы можете 50 раз в секунду рисовать абсолютно новую картинку. Но рисовать приходится каждый кадр с нуля. И только заслуга программистов что вы видите скроллы, коридоры, бегущих монстров и т.д. Естественно все это рисуется с помощью специальных интерфейсов взаимодействия с GPU (CUDA, Vulkan, OpenCL).

Для вашей задачи вы вполне можете использовать эти мощнейшие механизмы - грузить в видеопамять картинки (текстуры), аппаратно натягивать их на плоскость, аппаратно скроллить эту плоскость. Все инструменты для этого есть в стандартной палитре компонентов Delphi.

Ссылка на комментарий
  • 0
32 минуты назад, Евгений Корепов сказал:

Для вашей задачи вы вполне можете использовать эти мощнейшие механизмы

Это всё хорошо, да вот, не могу сделать плавное движение картинки, -> с чего и идём?

 

Изменено пользователем Letos
Ссылка на комментарий
  • 0
1 минуту назад, Letos сказал:

Например, на Спектруме было 1 байт - 8 пикселей

Я приводил вам пример работы скроллинга, а не спецификацию. 

Ссылка на комментарий
  • 0

для рисования на VCL я использовал библиотеку Asphyre, которая задействовала DirectX. Никаких проблем со скроллом/масштабированием не было.

На FMX такой же DirectX и рисование карты будет абсолютно таким же шустрым.

Я все равно не понимаю суть проблемы. Там главная проблема рисование карты подложки. Она обычно существует в виде тайлов. Эти тайлы фиксированного масштаба. Выбираем их и копируем на битмап, потом поверх прорисовываем  все собственные слои данных. Я делал битмап в 4 раза больше окна. Это позволяло не перерисовывать всё, а только динамические слои. И к скроллингу никаких абсолютно претензий не было. Наоборот, это работало в разы быстрее чем в браузере...

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

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

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...