|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Янв 2, 2004 16:12:18 Всегда мечтал написать оптимизированную функцию In Rectangle. Уже сто раз их писал, но все както до оптимизации дело не доходило. А тут... С головой ушел в программирование под DirectX. Делаю систему окон для игры. Там эта самая функция будет вызываться раз 100 в секунду. Надо бы написать оптимизированный вариант под современные процессоры. Задача такая: имеется прямоугольник с координатами (x,y),размерами (sx,sy) и координаты мышки (mx,my) Обычно проверка такая (только для x): if (mx>=x && mx<=x+sx) ... но можно еще так: a=mx-x; if (a>=0 && a<=sx) ... А как тоже самое написать на асме да еще с оптимизацией при условии, что функция должна возвращать 1 если мышка внутри прямоугольника и 0 в противном случае? |
|
|
Дата: Янв 2, 2004 17:02:03 · Поправил: S_T_A_S_ Доброго времени суток Я сейчас только начинаю погружаться с головой.. Возможно, мое мнение покажется странным. Оно базируется на древнем опыте написания окошек на спектруме. К сожалению, с терминологией у меня проблемы, попробую обьяснить на пальцах Создаем окно - т.е. рисуем его на сурфэйсе. Параллельно с этим рисеум "ТЕНЬ" окна в другом буфере. У каждого окна - свой "цвет" тени, т.е. разными байтами рисуем разные окна. Если окна нет - то цвет тени будут, скажем, 0. По нажатию мыши смотрим цвет тени. Все. При этом можно иметь круглые/треугольные окна. Можно в виде цвета тени использовать DWORD - адрес нужной процедуры. Тогда DWORD для фона будет являться поинтером на простой ret. Тут уж совсем без проверок :) Минус - тратим время на рисование "тени". Имхо, тратим меньше, чем приобретаем. Тут много зависит от конкретной реализации. В вашем случае, возможно, оптимальным будет использовать по биту на пиксель (т.е. один "цвет"). А может быть alpha канал.. А проверки мне никогда не нравились :) К тому же современные процессоры хорошо исполняют только предсказуемый код |
|
|
Дата: Янв 2, 2004 17:58:14 · Поправил: Black_mirrormov eax,mx;if (mx>=x && mx<x+sx) sub eax,x cmp eax,sx sbb eax,eax;eax=-1 else eax=0 mov edx,my;if (my>=y && my<y+sy) sub edx,y cmp edx,sy sbb edx,edx;edx=-1 else edx=0 and eax,edx;eax=-1 если внутри и eax=0 если снаружи ret |
|
|
Дата: Янв 2, 2004 18:46:02 Можно использовать API PtInRect или написать свою, например так: InRect proc x:DWORD, y:DWORD, wdth:DWORD, hght:DWORD, mx:DWORD, my:DWORD mov eax, mx cmp eax, x jl OutOfRect ; Mouse.X < Rect.Left sub eax, x cmp wdth, eax jle OutOfRect ; Mouse.X > Rect.Right mov eax, my cmp eax, y jl OutOfRect ; Mouse.Y < Rect.Top sub eax, y cmp hght, eax jle OutOfRect ; Mouse.Y > Rect.Bottom mov eax, TRUE ret OutOfRect: mov eax, FALSE ret InRect endp |
|
|
Дата: Янв 2, 2004 19:14:45 Black_mirror Спасибо! То, что надо!!! Предсказуемый код! без переходов по условию. Может быть за такт выполнится :) Сейчас попробую в сишке написать... S_T_A_S_ А как ты тень хранишь? Сурфэйсом? В видюхе или в оперативке? Я тоже об этом думал, но чето мне както не нравится функция ReadPixel еще с древних времен VGA. Я кстати так и не смог ее на VGA написать. Я думаю так: Сначала проверяем находится ли мышка на сурфэйсе, потом если это необходимо проверяем эту самую тень (если кнопка "кривая"). Если можешь дай ключевые куски кода или ссылку в инете почитать как эту тень сделать - пригодится. |
|
|
Дата: Янв 2, 2004 19:33:59 Кстати а если числа - float то как? |
|
|
Дата: Янв 2, 2004 20:45:28 Я протестил функцию с помошью RDTSC и вот результат: вызов этой функции bool GWnd::InRect() { return (input->x>=m_Rect.x && input->x<m_Rect.x+m_Rect.sx && input->y>=m_Rect.y && input->y<m_Rect.y+m_Rect.sy); } ~1500 тактов а этой bool GWnd::InRect() { int x = m_Rect.x; int y = m_Rect.y; int sx = m_Rect.sx; int sy = m_Rect.sy; int mx = input->x; int my = input->y; __asm { mov eax,mx sub eax,x cmp eax,sx sbb eax,eax mov edx,my sub edx,y cmp edx,sy sbb edx,edx and eax,edx } return; } ~3000 тактов Тоесть примерно в 2 раза медленнее. Я проверил - это из-за преобразования типов - они занимают примерно 2000 тактов. |
|
|
Дата: Янв 2, 2004 21:02:45 Куски кода для Z80? Дя они у меня на 5'25 флопах :) Я же это столет назад делал. Теперь вот опять начал. Сурфейс (я под этим понимаю весь экран) естественно в оперативке. Из видеопамяти чтение идет ОЧЕНЬ медленно. Потом копирую BltFast на бакбуфер и затем flip. Сначала проверяем находится ли мышка на сурфэйсе, потом если это необходимо проверяем эту самую тень Представим, что у нас только два цвета. Черный - фон. Белый - окна. Теперь можно просто определить, есть ли окно под мышью: посмотреть цвет пикселя. Но цветов-то на самом деле больше, поэтому ReadPixel не подходит. Поэтому и создается "черно-белая копия" экрана. С ней то проще работать, чем непосредственно с экраном. Это самый простой вариант. Он может лишь показать есть окно или нет. А если использовати не 1 бит на пиксель а DWORD, то можно сильно упростить логику работы программы. Например кнопку "закрыть окно" рисуем цветом "offset CloseWindow". Верхнюю часть окна - "offset MoveWindow". Перед этим очищаем буфер "цветом" "offset DoNothing" Теперь как просто обрабатывать нажатия мыши! Никаких проверок. Просто JMP Shadow[X*Y] Хотя рисование на экране несколько усложняется. Т.к. надо два раза рисовать. Но и тут есть несколько вариантов. Например можно использовать 32bpp и для наших целей использовать Alpha байт. Здесь красивый jmp уже не получится, надо будет табличку использовать. Если рисовать "ручками" (а я так и делаю), то можно просто записывать сразу в два места в памяти, т.е. скорость кода практически не изменится. Но вы немного опередили меня со своим вопросом. Я это еще не реализовал пока. Еще не решил в каком виде у меня окна будут. Это важный момент. Хотя.. подобный прием я использовал в новогодней деме. Там "снег" прилипает. У меня 2888 снежинок. Представляете, если бы были проверки? Про range-test (первый вопрос) можно еще посмотреть вот здесь Хорошие примеры. |
|
|
Дата: Янв 2, 2004 21:10:37 Кстати а если числа - float то как? Лучше использовать числа с фиксированной точкой. Например младшие 8 бит - дробная часть |
|
|
Дата: Янв 2, 2004 21:21:45 А кто нибудь может написать ту же проверку только для float ато я сопроцессор не очень знаю. Декомпилил то, что написал на си - ох и тупой же всетаки компилятор :-) Условный переход на каждой проверке а всего команд гдето 30-50. Всем спасибо за ответы! |
|
|
Дата: Янв 2, 2004 21:29:01 S_T_A_S_ А что за фиксированная точка - много раз слышал, но ни разу не видел. И как ее можно применить в директе - там же все вертексы - float векторы? |
|
|
Дата: Янв 2, 2004 23:18:31 И пусть будут float. Это для рендеринга на экран. Для ваших личных функций можно любые форматы использовать. Хотя мне сложно судить о вашей программе, т.к. я не знаю как вы окошки рисуете. Много окошек? Если много то любые InRect будут неэффективны, имхо. Особенно если будут перекрывающиеся окошки. Честно сказать, мне тоже окошки придется рисовать скоро и я не вижу других путей, кроме моего старого. Фиксированная запятая. Пусть есть два dword: X и Y. Обычно рисуем точку с координатами (X;Y). А можно с координатами, например, (X/256;Y/256). Т.е. получается, что для вывода на экран младший байт как-бы не нужен. Зато его можно использовать для "плавного" изменения координаты. Например увеличиваем на 2 каждый кадр. Реально же на экране точка сдвинется через 128 кадров. |
|
|
Дата: Янв 2, 2004 23:28:14 Для float примерно так: sub esp,16 fld [mx] fsub [x];mx-x fst dword [esp];<0(bit31=1) если не попадает fsub [sx];(mx-x)-sx=mx-(x+sx) fstp dword [esp+4];>0(bit31=0) если не попадает fld [my] fsub [y];my-y fst dword [esp+8];<0(bit31=1) если не попадает fsub [sy];my-(y+sy) fstp dword [esp+12];>0(bit31=0) если не попадает mov eax,[esp] or eax,[esp+8];bit31=0 если не попадает not eax and eax,[esp+4] and eax,[esp+12] shr eax,31;eax=1 если попадает и eax=0 если не попадает add esp,16 |
|
|
Дата: Янв 3, 2004 07:18:53 S_T_A_S_ А операция деления? Ну ладно сдвиг на 8 вправо если я не ошибаюсь занимает по 2 такта на 1 бит. И это окупается? Вроде бы современные процессоры с float работают ничуть не хуже, чем с DWORD. Правда с преобразованием типов проблемы. Я както писал РГР по программированию в универ - игра арканоид. Так вот в ней я все сделал на целочисленной арифметике. А мой одногрупник написал арканоида на float так у него плавность движения мячика была куда лучше, чем у меня. А скорость не пострадала. На счет оконной системы - у меня дерево. В корне пустое окно, от которого расходятся ветки. Активно используется наследование и полиморфизм. События - указатели на функции типа OnClick и тп. Так что много окон опрашиваться не будут. Black_mirror Сейчас попробую... |
|
|
Дата: Янв 3, 2004 10:09:36 · Поправил: profi_r Протестил - ~2500 тактов. Все равно медленно...
bool GWnd::InRect()
{
float x = m_Rect.x;
float y = m_Rect.y;
float sx = m_Rect.sx;
float sy = m_Rect.sy;
float mx = input->x;
float my = input->y;
int a,b,c,d;
__asm
{
fld mx
fsub x
fist a
fsub sx
fistp b
fld my
fsub y
fist c
fsub sy
fistp d
mov eax,a
or eax,c
not eax
and eax,b
and eax,d
rol eax,1
}
return;
}
|
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.058 |