- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Графика для Windows средствами DirectDraw - Стэн Трухильо
Шрифт:
Интервал:
Закладка:
Наконец, основной поток должен предупредить поток ввода о завершении приложения. Помните — поток ввода работает независимо от основного потока. Без извещения со стороны основного потока он не будет знать о том, что приложение собирается завершиться. Кроме того, основной поток не может просто остановить работу потока ввода; поток ввода должен завершиться сам при получении сигнала завершения от основного потока.
Поток вводаПоток ввода обладает более узкой специализацией по сравнению с основным потоком. Он должен делать следующее:
• обнаруживать ввод от мыши;
• обновлять курсор;
• синхронизироваться с основным потоком;
• обрабатывать сигнал завершения, полученный от основного потока.
Для получения ввода от мыши могут применяться две схемы: опрос и оповещение. Опрос плохо подходит для нашего случая, потому что поток ввода постоянно остается активным, даже если пользователь не работает с мышью. С другой стороны, если поток ввода блокируется до поступления новых данных от мыши, он почти не расходует лишнего процессорного времени. С помощью имеющегося в DirectInput механизма оповещения можно заблокировать поток ввода до тех пор, пока DirectInput не сообщит о поступлении новых данных.
После получения сигнала поток ввода извлекает новые данные и обновляет курсор одним из двух способов, рассмотренных выше. Независимо от того, какой способ будет использован, обновление курсора необходимо синхронизировать с основным потоком, чтобы потоки не пытались обратиться к первичной поверхности одновременно.
Наконец, поток ввода отвечает за свое завершение. При получении сигнала от основного потока он должен прекратить работу.
Что делать с кнопками мыши?В начале этой главы мы решили создать курсор, который не мерцает и мгновенно реагирует на перемещения мыши при любой частоте вывода кадров. Нам удалось спроектировать (не считая собственно кодирования) решение, удовлетворяющее этим критериям. Многопоточность позволила отделить ввод мыши от приложения. Если не считать исходного запуска потока ввода и синхронизации, наш основной поток решает общие задачи приложения и не занимается получением ввода.
Но стоит ли полностью изолировать приложение от мыши? Если основной поток ничего не знает о том, что происходит с мышью, мы не сможем пользоваться мышью в приложении.
Мы поступили правильно, удалив получение данных о перемещениях мыши из основного потока, но что делать с кнопками мыши? Необходимо придумать, как сообщать основному потоку об изменениях их состояния.
Поток ввода уже занимается получением данных от мыши, поэтому возможное решение проблемы — заставить его сохранять сведения о кнопках в очереди. Затем основной поток сможет получить эти данные, проверяя содержимое очереди.
Поскольку очередь совместно используется двумя потоками, нам придется позаботиться о синхронизации. В каждом потоке уже присутствует поддержка критических секций, так что добиться синхронизации будет нетрудно.
Программа Cursor
Программа Cursor использует описанную выше методику и выводит на экран изображение вращающейся спирали, меню задержки и курсор мыши. По умолчанию программа выводит кадры максимально часто, но меню задержки позволяет уменьшить частоту вывода за счет задержки в основном потоке (максимальная задержка равна 500 миллисекундам, при этом приложение замедляется до 2 FPS). Если бы курсор не управлялся отдельным потоком, его обновление происходило бы лишь с выводом очередного кадра. Но поскольку курсор мыши не зависит от основного потока, он нормально реагирует на действия пользователя при любой частоте вывода. Программа Cursor изображена на рис. 7.1.
Рис. 7.1. Программа Cursor
Перед тем как погружаться в программный код, я должен признаться, что работа над программой Cursor сопровождалась внутренней борьбой. Мне очень хотелось разбить код на несколько мелких функций, скрыть некоторые технические подробности и упорядочить структуру программы. Однако я справился с искушением — читатель наверняка захочет видеть программу прямо перед собой, вместо того чтобы искать нужный фрагмент по всему коду. В результате программа получилась менее структурированной по сравнению с другими.
СОВЕТКак создать собственный курсор
Программа Cursor может работать с курсором любого размера. В версии программы на CD-ROM использован небольшой курсор (12×20 пикселей), но вы можете легко изменить этот стандартный размер. Для этого достаточно заменить cursor_08.bmp и/или cursor_24.bmp файлами с более крупными изображениями курсоров.
По умолчанию приложение работает в 8-битном видеорежиме и соответственно с 8-битным курсором. Многое зависит от вашего графического редактора, но, скорее всего, вы избавитесь от проблем с палитрой, если воспользуетесь файлом cursor_08.bmp с CD-ROM как шаблоном для создания нестандартного курсора. С курсором формата True Color дело обстоит проще, но, чтобы воспользоваться им, придется слегка подправить функцию SelectInitialDisplayMode(), чтобы активизировать беспалитровый видеорежим вместо палитрового.
Класс CursorWinПрограмма Cursor, как и все остальные программы этой книги, построена на базе структурных классов DirectDrawWin и DirectDrawApp. Эти классы остались неизменными, а вся специфика приложения реализуется классом CursorWin. На практике функциональность курсора мыши, вероятно, следовало бы встроить в структурный класс. И все же для наглядности я объединил код для работы с курсором со специфическим кодом приложения. Класс CursorWin приведен в листинге 7.1.
Листинг 7.1. Класс CursorWin
class CursorWin : public DirectDrawWin {
public:
CursorWin();
protected:
//{{AFX_MSG(CursorWin)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
int SelectDriver();
int SelectInitialDisplayMode();
BOOL CreateCustomSurfaces();
void DrawScene();
void RestoreSurfaces();
private:
BOOL InitMouse();
BOOL InitKeyboard();
BOOL UpdateDelaySurface();
private:
//------- Функции потока ввода ------
static DWORD MouseThread(LPVOID);
BOOL UpdateCursorSimpleCase(int curx, int cury, int oldcurx, int oldcury);
BOOL UpdateCursorComplexCase(int curx, int cury, int oldcurx, int oldcury);
private:
//------- Данные мыши -------
static LPDIRECTINPUTDEVICE mouse;
static CCriticalSection critsection;
static CWinThread* mousethread;
static CEvent* mouse_event[2];
static int cursor_width;
static int cursor_height;
static LPDIRECTDRAWSURFACE cursor;
static LPDIRECTDRAWSURFACE cursor_under;
static LPDIRECTDRAWSURFACE cursor_union;
static int curx, cury;
static int oldcurx, oldcury;
static CList<MouseClickData, MouseClickData> mouseclickqueue;
private:
//------- Данные приложения -------
LPDIRECTINPUT dinput;
LPDIRECTINPUTDEVICE keyboard;
LPDIRECTDRAWSURFACE coil[coil_frames];
LPDIRECTDRAWSURFACE dm_surf;
int dm_index;
DWORD menubarfillcolor;
HFONT largefont, smallfont;
};
Класс CursorWin объявляет три обработчика сообщений: OnCreate(), OnDestroy() и OnActivate(). Функция OnCreate() инициализирует DirectDraw, DirectInput и поток ввода. Функция OnDestroy() освобождает интерфейсы DirectX и завершает поток ввода. Функция OnActivate() обеспечивает захват мыши и клавиатуры на период активности приложения.
Следующие пять функций наследуются от класса DirectDrawWin:
• SelectDriver()
• SelectInitialDisplayMode()
• CreateCustomSurfaces()
• DrawScene()
• RestoreSurfaces()
Мы достаточно часто видели эти функции в других приложениях и знаем, что они делают, поэтому не будем рассматривать их. Исключением является функция DrawScene(), которая представляет некоторый интерес, потому что помимо создания нового кадра занимается синхронизацией основного потока с потоком ввода.
Затем объявляются функции InitMouse() и InitKeyboard(). Эти функции используются функцией OnCreate() и отвечают за инициализацию объектов DirectInput, предназначенных для работы с мышью и клавиатурой. Функция InitKeyboard() совпадает с одноименными функциями программ Qwerty и Smear из главы 6, поэтому она также не рассматривается. Однако функция InitMouse() помимо инициализации мыши запускает поток ввода. Вскоре мы рассмотрим эту функцию.
Функция UpdateDelaySurface() готовит к выводу поверхность меню задержки. Она выводит текст меню и выделяет текущую задержку.
Далее в классе CursorWin объявляются три функции потока мыши: