- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Графика DirectX в Delphi - Михаил Краснов
Шрифт:
Интервал:
Закладка:
Прежде всего, необходимо указать, задается ли исключительный доступ к устройству или нет (флаги DISCL_EXCLUSIVE и DISCL_NONEXCLUSIVE). В этом примере устанавливаю неисключительный доступ. Для стандартного устройства разница между ними невелика, библиотека Directlnput не может позволить никакому приложению захватить клавиатуру монопольно. Просто эксклюзивный доступ может привести к помехам в работе с устройством других приложений.
Помимо эксклюзивности обязательно необходимо задать активность режима (указать один из флагов DISCL^BACKGROUND или DISCL_FOREGROOND). Первый флаг соответствует режиму, когда приложение имеет доступ к устройству ввода всегда, даже когда не имеет активности. Если вы запустите две копии этой программы, то обе они будут реагировать на нажатие клавиш, и по нажатии клавиши <Esc> завершат работу обе копии.
Следующие действия при инициализации связаны с выбранной схемой получения доступа к данным. Можно использовать данные двух видов: непосредственные (immediate) и буферизованные (buffered).
При работе с клавиатурой по первой схеме приложение периодически опрашивает клавиши, получая данные о каждой из них: нажата она или нет. Вторая схема состоит в том, что приложение считывает буфер, в котором хранятся данные о произошедших со времени последнего опроса событиях связанных с устройством: какие клавиши были нажаты, какие были отпущены.
Наш пример позволяет применить обе схемы, но первоначально настроен на вторую, буферизованную, схему. Для нее надо задать размер буфера, и поэтому используется вспомогательная структура, передающаяся аргументом метода setProperty. Размер буфера мы задаем равным значению константы проекта:
const
SAMPLE_BUFFER_SIZE = 8;
Запомните, что для схемы непосредственного опроса эти действия не нужны.
Заканчивается код инициализации захватом устройства, получением доступа к нему, вызовом метода Acquire объекта, связанного с устройством. Теперь мы можем получать данные с устройства, если оно доступно и все подготовительные шаги были успешны.
Вызывается код инициализации при создании формы, в случае неудачи выводится сообщение:
procedure TfrmDX.FormCreate(Sender: TObject);
var
hRet : HRESULT;
begin
hRet := OnCreateDevice; // Инициализация устройства
if Failed (hRet) then MessageDlg(DIErrorString(Error), mtError,
[mbAbort], 0);
end;
Ошибки возможны при неверном указании параметров, также они появляются при занятости устройства. Если сейчас запущено приложение, имеющее исключительный доступ к клавиатуре, то у нас могут возникнуть проблемы с захватом устройства. В этой ситуации следует вызывать метод Acquire до тех пор, пока не будет установлена связь.
В нашем примере, после установления связи с устройством происходит беспрерывный вызов функции чтения буферизованных данных:
function TfrmDX.ReadBufferedData : HRESULT;
var
didod : Array [0..SAMPLE_BUFFER_SIZE - 1] of TDIDEVICEOBJECTDATA;
dwElements : DWORD;
i : DWORD;
hRet : HRESULT;
s : String;
begin
if DIKeyboard = nil then begin
Result := DI_OK;
Exit
end;
// Считываем данные из буфера
hRet := DIKeyboard.GetDeviceData (SizeOf(TDIDEVICEOBJECTDATA),
@didod, dwElements, 0);
if Failed (hRet) then begin // Восстанавливаем связь
hRet := DIKeyboard.Acquire;
while hRet = DIERR_INPUTLOST do
hRet := DIKeyboard.Acquire;
end;
// Буфер не пустой
if dwElements <> 0 then
for i := 0 to dwElements - 1 do begin
if didod[i].dwData and $80 <> 0 // Клавиша нажата
then s := 'D'
else s := 'U';
Memol.Lines.Add (Format ('Ox%02x%s', [didod[i].dwOfs, s] ) ) ;
if didod[i] .dwOfs = DIK__ESCAPE then Close;
end;
Result := DI_OK; // Нулевое значение, признак успешности
end;
Метод GetDeviceData объекта, ассоциированного с устройством, позволяет осуществить собственно считывание данных из буфера. Смысл первого аргумента прозрачен: это размер структуры, предназначенной для хранения. Второй аргумент - указатель на массив элементов данной структуры. В качестве значения третьего аргумента устанавливается количество считанных из буфера данных. Последний аргумент может быть нулем или константой DIGDD_PEEK (во втором случае буфер не будет очищаться после считывания данных).
Если функция возвращает ненулевое значение, то, скорее всего, потеряна связь с устройством. Тогда необходимо снова установить эту связь, вызвав метод Acquire. В библиотеке Directlnput отсутствуют какие-либо специальные методы восстановления, а устанавливать связь можно сколько угодно раз, т. к. лишние вызовы этой функции игнорируются.
Скан-коды клавиш содержатся в поле dwOfs структуры TDIDEVICEOBJECTDATA, значение поля dwData позволяет узнать, какое событие произошло, нажата ли клавиша или отпущена. Если это значение равно 128, то клавиша опущена. В нашем примере к коду клавиши в этом случае приписывается буква "D", иначе - "U".
Вам не обязательно помнить наизусть коды всех клавиш, можете пользоваться символическими константами. Для примера я показал, как выделить нажатие клавиши <Esc>.
После завершения работы освобождаем устройство и память, занятую объектами:
procedure TfrmDX.FormDestroy(Sender: TObject);
begin oif Assigned (DIKeyboard) then DIKeyboard.Unacquire; // Завершить диалог
if Assigned (DIKeyboard) then DIKeyboard := nil;
if Assigned (DInput) then DInput := nil;
end;
Поработайте с примером и обратите внимание, что можно отследить состояние максимум четырех клавиш одновременно.
Непосредственная схема работы с клавиатурой используется чаще, чем буферизованная, напоминаю, что состоит она в том, что в необходимые моменты происходит опрос всех клавиш. Удалите из кода обработчика onidle вызов процедуры буферного опроса клавиатуры и снимите комментарий со следующей далее строки. В коде инициализации удалите все, связанное с заданием размера буфера. Запустите проект и нажмите несколько клавиш (тоже максимум четыре) одновременно, в Memo выведутся коды всех нажатых клавиш:
function TfrmDX.ReadlinmediateData : HRESULT;
var
hRet : HRESULT;
diks : Array [0..255] of BYTE; // Массив состояния клавиатуры
i : Integer;
sMulti : String;
begin
if DIKeyboard = nil then begin
Result := DI_OK;
Exit
end;
ZeroMemory(@diks, SizeOf(diks)); // Подготавливаем массив
hRet := DIKeyboard.GetDeviceState(SizeOf(diks), Sdiks); // Заполняем
if Failed (hRet) then begin // Требуется восстановить связь
hRet := DIKeyboard.Acquire;
while hRet = DIERR_INPUTLOST do
hRet := DIKeyboard.Acquire;
end;
sMulti := '';
for i := 0 to 255 do // Вывод кодов нажатых клавиш
if diks[i] and $80 <> 0
then sMulti := sMulti + ' ' + Format ('Ox%02x', [i]);
Memol.Lines.Add (sMulti);
Result := DI_OK;
end;
Непосредственная схема основана на использовании метода GetDeviceState, по вызову которого массив заполняется данными о состоянии клавиш, точно также здесь возможны значения 0 и 128.
В примере происходит опрос состояния всех клавиш, что не обязательно делать, если вас интересуют только некоторые из них. Например, если требуется осуществить выход по нажатии клавиши <Esc>, можно не пробегать в цикле по всем элементам массива, а обратиться только к единственному:
if diks [DIK^ESCAPE] = 128 then Close;
С помощью непосредственной схемы доступа легко обрабатывать нажатие нескольких клавиш одновременно, чем и пользуются часто в играх, как, например, в очередном примере - проекте каталога Ех06. От предыдущего варианта нашей тестовой игры пример отличается только тем, что здесь для управления используется библиотека Directlnput. Скорость ввода стала чрезвычайно стремительной, воин теперь резво передвигается по нажатии клавиш, буквально быстрее пули. Хотя шаг его нисколько не увеличился. Одним махом происходит обработка нескольких клавиш, и можно, например, стрелять вверх и вбок одновременно, или двигаться вправо и стрелять вверх. Пули тоже вылетают на порядок быстрее, и ограничение в сотню расходуется в считанные секунды.
Принципиально обработка ввода ничем не отличается от первого примера на основе библиотеки Directlnput. Здесь используется непосредственная схема доступа, только уровень доступа устанавливается в комбинацию
DISCL_FOKEGROUND or DISCL_EXCLUSIVE. Несмотря на негласное соглашение,
что неактивное приложение не будет считывать данные с клавиатуры, при запуске двух копий программы обе они сильно замедлятся.
Работа с мышью
После знакомства с возможностями ввода с клавиатуры нам будет легко научиться работать с мышью, принципы обработки ввода здесь точно такие же. Непосредственную схему доступа изучим на конкретном примере - проекте каталога Ех07. Это еще один вариант создания эффекта лупы, но более эффектный, чем предыдущие, поскольку здесь добавлены сферические искажения пикселов (рис. 5.7).
Представленные ниже константы и переменные связаны с параметрами искажений:
const
Diameter = 180; // Задает максимальный размер лупы
Scale =35; // Вспомогательный коэффициент
var
Radius : Integer = Diameter div 2; // Текущий размер лупы
SqrRad : Integer; // Вспомогательные величины
Sphere : Integer;
Вспомогательные переменные заполняются первоначально при создании формы:
SqrRad := Radius * Radius; // Квадрат радиуса
Sphere := (Radius * Radius) - (Scale * Scale); // Искажение
Во время перерисовки кадра накладываем фон, а искажения вносим сразу на поверхность заднего буфера:

