Как быстро рисовать bmp в перспективе без OpenGL и DirectX

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Sheleh
новенький
Сообщения: 24
Зарегистрирован: 12.11.2010 17:31:07

Как быстро рисовать bmp в перспективе без OpenGL и DirectX

Сообщение Sheleh »

Делаю тайловый (как googlemap) картографический двиг. Пока все работает в плоскости экрана, но есть мысль выводить карту под наклоном для придания эффекта перспективы. И вот возникает вопрос: как нарисовать квадратное изображение по новым изометрическим координатам. Может уже есть какая-нибудь функция типа DrawStretch, но рисующая BitMap не по двум точкам, а по 4-м?

Изображение Изображение
Последний раз редактировалось Sheleh 06.12.2010 10:01:03, всего редактировалось 2 раза.
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Вам же предложили воспользоваться OpenGL. Почему упрямитесь?
Sheleh
новенький
Сообщения: 24
Зарегистрирован: 12.11.2010 17:31:07

Сообщение Sheleh »

Вам же предложили воспользоваться OpenGL. Почему упрямитесь?
Потому что:
1. Ни разу не работал с OpenGL;
2. OpenGL, что работает под windows не компилируется под WinCE;
3. Не могу найти OpenGL, кторый бы работал на любом WM устройстве. Даже просто набирая в поисковике слова OpenGL+Lazarus+WinCE не находится ничего внятного.
4. Хочется поломать мозг с преобразованием плоских координат в изометрические;
5. Я пишу не 3D шутер, а всего лишь обычную плоскость с наклоном, так что возможно и не требуется использование вычислительной мощи видеоустройств;
6. Да и осталось всего лишь придумать как выводить картинку в свободном вращении/искажении.
Аватара пользователя
Nik
энтузиаст
Сообщения: 573
Зарегистрирован: 03.02.2006 23:08:09
Откуда: Киров
Контактная информация:

Сообщение Nik »

6. Да и осталось всего лишь придумать как выводить картинку в свободном вращении/искажении.

Попробуйте поискать алгоритм такого преобразования изображений. В Сети наверняка есть (не факт, что для Delphi/Lazarus).
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

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

эффект перспективы без собственно перспективы не получить. выводить под наконом - получится под наклоном вся вся картинка (т.е. сплюснутая), а не ближние объекты больше, дальние меньше.
пошарте http://www.crossgl.com/aggpas/aggpas-demo.htm, там вроде было перспективное искажение растров.

также можно погуглить алгоритмы текстурирования
Sheleh
новенький
Сообщения: 24
Зарегистрирован: 12.11.2010 17:31:07

Сообщение Sheleh »

эффект перспективы без собственно перспективы не получить. выводить под наконом - получится под наклоном вся вся картинка (т.е. сплюснутая), а не ближние объекты больше, дальние меньше.
Да это понятно. Я надеюсь добиться эффекта с помощью сетки. Чем дальше, тем чаще будет сетка, как на втором рисунке. Вроде должно получится.
Sheleh
новенький
Сообщения: 24
Зарегистрирован: 12.11.2010 17:31:07

Сообщение Sheleh »

решил попробовать самостоятельно реализовать процедуру пространственного искажения хотя бы безо всяких сглаживаний. Для начала заменил
ImageLayer.Canvas.Draw(x,y,BmpCache[]);

попиксельным копированием изображения обычными методами:
for i:=0 to 255 do
for j:=0 to 255 do
begin
ImageLayer.canvas.pixels[i+x,j+y]:=BmpCache[].canvas.pixels[i,j];
end;


В ответ получил страшенные тормоза, и в связи с этим назрел новый вопрос: как быстро считать пиксель из TBitmap и вывести его на TImage.canvas? Желательно что бы это работало и для Win32 и для WinCE
.wOvAN
постоялец
Сообщения: 118
Зарегистрирован: 16.04.2010 06:36:12
Контактная информация:

Сообщение .wOvAN »

Sheleh Выводить на TImage.canvas нужно уже готовую картинку, а пиксели копировать на невидимый битмап. Это вероятно ускорит процесс.
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

И для попиксельной обработки производительнее будет если использовать TLazIntfImage - в папке с лазарусом (Examples) есть пример как это использовать, там есть прямой доступ к памяти изображения. В Делфи был аналогично производительный способ доступа к памяти изображения через сканлайны битовой карты, но в Лазарусе отчего-то сделали иначе..
alexrayne
постоялец
Сообщения: 125
Зарегистрирован: 03.12.2008 15:56:26

Сообщение alexrayne »

Mr.Smart писал(а):Потому что:1. Ни разу не работал с OpenGL;

Ну а directX почему неустраивает? на старых вендах он был даже пошустрее опенГЛа, ибо опенГЛ был сделан как обертка директа.

Добавлено спустя 2 минуты 9 секунд:
Я етот вопрос к тому что упаритесь вы попиксельно картинку перспективить, вы добьетесь того что страшные тормоза станут просто тормозами, думаете что этого вам хватит?
Sheleh
новенький
Сообщения: 24
Зарегистрирован: 12.11.2010 17:31:07

Сообщение Sheleh »

FedeX писал(а):И для попиксельной обработки производительнее будет если использовать TLazIntfImage - в папке с лазарусом (Examples) есть пример как это использовать, там есть прямой доступ к памяти изображения. В Делфи был аналогично производительный способ доступа к памяти изображения через сканлайны битовой карты, но в Лазарусе отчего-то сделали иначе..
Попробовал, работа с пикселями вроде не тормозная, но вот что бы результат вывести на канаву сначала надо сформировать битмап
TempIntfImg.CreateBitmaps(ImgHandle,ImgMaskHandle,true);
, что происходит достаточно долго.

В общем я нашел более простой альтернативный способ прямого доступа к пикселям битмапа - API функция CreateDIBSection (win32, wince). В аттаче находится пример, демонстрирующий производительность (белый шум) на Delphi (у меня 6-ка стоит). Но я не могу перенести его на лазарус, он не узнает структуру tagBITMAPINFO, которая должна находится в модуле Windows. Господа специалисты, помогите добавить эту структуру
var
BInfo: tagBITMAPINFO; Error: Identifier not found "tagBITMAPINFO"
begin
// Создание DIB
BInfo.bmiHeader.biSize := sizeof(tagBITMAPINFOHEADER);
BInfo.bmiHeader.biWidth := SX;
BInfo.bmiHeader.biHeight := -SY;
BInfo.bmiHeader.biPlanes := 1;
BInfo.bmiHeader.biBitCount := 32;
BInfo.bmiHeader.biCompression := BI_RGB;
ScrBitmap := TBitmap.Create();
ScrBitmap.Handle := CreateDIBSection(ScrBitmap.Canvas.Handle, BInfo, DIB_RGB_COLORS, Scr, 0, 0);
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

просто подключи модуль bmpcomn.pp ,там есть эта структура, хотя и называеться TBitMapInfoHeader. Просто tagBITMAPINFO содержит ее в себе и вроде больше ничего кроме неё, возможно ввиду того, что в заголовке битмапа могут быть ещё иные данные (но как правило их нет). Это только предположение - давно с винапи не работал.
Sheleh
новенький
Сообщения: 24
Зарегистрирован: 12.11.2010 17:31:07

Сообщение Sheleh »

FedeX
Вот, согласно предположению, действительно есть в TBitMapInfoHeader нужные записи:
var
BInfo: TBitMapInfoHeader;
//tagBITMAPINFO;
begin
// Создание DIB
SX := aSX; SY := aSY;
BInfo.Size:=sizeof(BInfo);
BInfo.Width := SX;
BInfo.Height := -SY;
BInfo.Planes := 1;
BInfo.BitCount := 32;
BInfo.Compression := BI_RGB;
ScrBitmap := TBitmap.Create();
ScrBitmap.Handle := CreateDIBSection(ScrBitmap.Canvas.Handle, BInfo, DIB_RGB_COLORS, Scr, 0, 0);

Только теперь компилятор ругается на несоответствие типов:
Error: Call by var for arg no. 2 has to match exactly: Got "TBitMapInfoHeader" expected "BITMAPINFO"
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

Вообщем я не правильно предположил tagBITMAPINFO содержит ещё поле bmiColors : array[0..0] of RGBQUAD; которое правда действительно можно опустить если изображение не содержит палитры..
http://msdn.microsoft.com/en-us/library/dd183375%28VS.85%29.aspx.
Я ещё раз воспользовался полнотекстовым поиском по файловой системе (из JEdit) и обнаружил правильную структуру соответствующую tagBITMAPINFO - BITMAPINFO. Она находиться в файле struct.inc который поидее должен быть подключен к модулю Windows . Попробуй просто в заголовке своего модуля или в другом месте написать: {$IFDEF FPC}type tagBITMAPINFO=TBITMAPINFO;{$ENDIF}
Sheleh
новенький
Сообщения: 24
Зарегистрирован: 12.11.2010 17:31:07

Сообщение Sheleh »

написал во так:
procedure TForm1.CreateBitmap(aSX, aSY: Integer);
var
BInfo: TBitmapInfo;
begin
// Создание DIB
SX := aSX; SY := aSY;
BInfo.bmiHeader.biSize := sizeof(BitmapInfo.bmiHeader);
BInfo.bmiHeader.biWidth := SX;
BInfo.bmiHeader.biHeight := -SY;
BInfo.bmiHeader.biPlanes := 1;
BInfo.bmiHeader.biBitCount := 32;
BInfo.bmiHeader.biCompression := BI_RGB;
ScrBitmap := TBitmap.Create();
ScrBitmap.Handle := CreateDIBSection(ScrBitmap.Canvas.Handle, BInfo, DIB_RGB_COLORS, Scr, 0, 0);
ZeroMemory(Scr, SX * SY * 4);
end;

Работает на 100%

Добавлено спустя 2 часа 12 минут 33 секунды:
Ура!!!

В общем сделал пока так: кэш тайлов теперь храню не в TBitmap, а в TLazIntfImage - из него быстрее всего считывать пиксели, а вывожу на канаву с помощью CreateDIBSection. На разрешении 1280х1024 есть небольшая задержка движения изображения за указателем, но это уже совсем не те тормоза, которые были раньше. Плюс для каждого пикселя у меня происходит проверка, что бы он не зашел за границы экрана, а это 4 условия с операциями сложения. Это надо будет оптимизировать и продумать возможность использования 8-ми битных изображений.
Ответить